ESP8266 NodeMCU Веб-сервер: отображение показаний датчиков на шкалах (Gauges)
Узнайте, как создать веб-сервер на ESP8266 NodeMCU для отображения показаний датчиков на шкалах (gauges). В качестве примера мы отобразим температуру и влажность с датчика BME280 на двух различных шкалах: линейной и радиальной. Вы можете легко модифицировать проект для отображения любых других данных. Для создания шкал мы будем использовать JavaScript-библиотеку canvas-gauges.
У нас есть аналогичное руководство для платы ESP32: Веб-сервер – Отображение показаний датчиков на шкалах
Обзор проекта
В этом проекте мы создадим веб-сервер на ESP8266, отображающий показания температуры и влажности с датчика BME280. Мы создадим линейную шкалу, которая выглядит как термометр, для отображения температуры, и радиальную шкалу для отображения влажности.
Server-Sent Events
Показания автоматически обновляются на веб-странице с помощью Server-Sent Events (SSE).
Чтобы узнать больше о SSE, вы можете прочитать:
Файлы, сохранённые в файловой системе
Для лучшей организации проекта и простоты понимания мы сохраним файлы HTML, CSS и JavaScript для построения веб-страницы в файловой системе платы (LittleFS).
Предварительные требования
Убедитесь, что вы выполнили все предварительные требования из этого раздела, прежде чем продолжить работу с проектом.
1. Установка платы ESP8266 в Arduino IDE
Мы будем программировать ESP8266 с помощью Arduino IDE. Поэтому у вас должно быть установлено дополнение ESP8266. Следуйте следующему руководству, если вы ещё этого не сделали:
Если вы хотите использовать VS Code с расширением PlatformIO, следуйте следующему руководству, чтобы узнать, как программировать ESP8266:
2. Плагин загрузки файловой системы
Для загрузки файлов HTML, CSS и JavaScript в файловую систему ESP8266 (LittleFS) мы будем использовать плагин для Arduino IDE: LittleFS Filesystem Uploader. Следуйте следующему руководству для установки плагина загрузки файловой системы:
Если вы используете VS Code с расширением PlatformIO, прочитайте следующее руководство, чтобы узнать, как загрузить файлы в файловую систему:
3. Установка библиотек
Для создания этого проекта вам необходимо установить следующие библиотеки:
Вы можете установить эти библиотеки с помощью Arduino Library Manager. Перейдите в Sketch > Include Library > Manage Libraries и найдите названия библиотек.
Необходимые компоненты
Для выполнения этого руководства вам понадобятся следующие компоненты:
ESP8266 (читайте Лучшие платы разработки ESP8266)
Вы можете использовать любой другой датчик или отображать любые другие значения, которые полезны для вашего проекта. Если у вас нет датчика, вы также можете экспериментировать со случайными значениями, чтобы узнать, как работает проект.
Вы можете использовать ссылки выше или перейти непосредственно на MakerAdvisor.com/tools, чтобы найти все компоненты для ваших проектов по лучшей цене!
Схема подключения
Мы будем отправлять показания температуры и влажности с датчика BME280. Мы собираемся использовать I2C-связь с модулем датчика BME280. Для этого подключите датчик к стандартным выводам ESP8266 SCL (GPIO 5) и SDA (GPIO 4), как показано на следующей схеме.
Рекомендуемое чтение: Справочник по распиновке ESP8266: какие выводы GPIO следует использовать?
Организация файлов
Для поддержания организованности проекта и облегчения его понимания мы создадим четыре файла для построения веб-сервера:
Скетч Arduino, который обрабатывает веб-сервер;
index.html: для определения содержимого веб-страницы;
style.css: для стилизации веб-страницы;
script.js: для программирования поведения веб-страницы — обработки ответов веб-сервера, событий, создания шкал и т.д.
Вы должны сохранить файлы HTML, CSS и JavaScript внутри папки с именем data внутри папки скетча Arduino, как показано на предыдущей диаграмме. Мы загрузим эти файлы в файловую систему ESP8266 (LittleFS).
Вы можете скачать все файлы проекта:
HTML-файл
Скопируйте следующее в файл index.html.
<!DOCTYPE html>
<html>
<head>
<title>ESP IOT DASHBOARD</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="style.css">
<script src="http://cdn.rawgit.com/Mikhus/canvas-gauges/gh-pages/download/2.1.7/all/gauge.min.js"></script>
</head>
<body>
<div class="topnav">
<h1>ESP WEB SERVER GAUGES</h1>
</div>
<div class="content">
<div class="card-grid">
<div class="card">
<p class="card-title">Temperature</p>
<canvas id="gauge-temperature"></canvas>
</div>
<div class="card">
<p class="card-title">Humidity</p>
<canvas id="gauge-humidity"></canvas>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
HTML-файл для этого проекта очень простой. Он подключает JavaScript-библиотеку canvas-gauges в заголовке HTML-файла:
<script src="https://cdn.rawgit.com/Mikhus/canvas-gauges/gh-pages/download/2.1.7/all/gauge.min.js"></script>
Существует тег <canvas> с идентификатором gauge-temperature, где мы позже отрисуем шкалу температуры.
<canvas id="gauge-temperature"></canvas>
Также есть ещё один тег <canvas> с идентификатором gauge-humidity, где мы позже отрисуем шкалу влажности.
<canvas id="gauge-humidity"></canvas>
CSS-файл
Скопируйте следующие стили в файл style.css. Он стилизует веб-страницу с помощью простых цветов и стилей.
html {
font-family: Arial, Helvetica, sans-serif;
display: inline-block;
text-align: center;
}
h1 {
font-size: 1.8rem;
color: white;
}
p {
font-size: 1.4rem;
}
.topnav {
overflow: hidden;
background-color: #0A1128;
}
body {
margin: 0;
}
.content {
padding: 5%;
}
.card-grid {
max-width: 1200px;
margin: 0 auto;
display: grid;
grid-gap: 2rem;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
background-color: white;
box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
font-size: 1.2rem;
font-weight: bold;
color: #034078
}
JavaScript-файл (создание шкал)
Скопируйте следующее в файл script.js.
// Get current sensor readings when the page loads
window.addEventListener('load', getReadings);
// Create Temperature Gauge
var gaugeTemp = new LinearGauge({
renderTo: 'gauge-temperature',
width: 120,
height: 400,
units: "Temperature C",
minValue: 0,
startAngle: 90,
ticksAngle: 180,
maxValue: 40,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueDec: 2,
valueInt: 2,
majorTicks: [
"0",
"5",
"10",
"15",
"20",
"25",
"30",
"35",
"40"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 30,
"to": 40,
"color": "rgba(200, 50, 50, .75)"
}
],
colorPlate: "#fff",
colorBarProgress: "#CC2936",
colorBarProgressEnd: "#049faa",
borderShadowWidth: 0,
borders: false,
needleType: "arrow",
needleWidth: 2,
needleCircleSize: 7,
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear",
barWidth: 10,
}).draw();
// Create Humidity Gauge
var gaugeHum = new RadialGauge({
renderTo: 'gauge-humidity',
width: 300,
height: 300,
units: "Humidity (%)",
minValue: 0,
maxValue: 100,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueInt: 2,
majorTicks: [
"0",
"20",
"40",
"60",
"80",
"100"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 80,
"to": 100,
"color": "#03C0C1"
}
],
colorPlate: "#fff",
borderShadowWidth: 0,
borders: false,
needleType: "line",
colorNeedle: "#007F80",
colorNeedleEnd: "#007F80",
needleWidth: 2,
needleCircleSize: 3,
colorNeedleCircleOuter: "#007F80",
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear"
}).draw();
// Function to get current readings on the webpage when it loads for the first time
function getReadings(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
console.log(myObj);
var temp = myObj.temperature;
var hum = myObj.humidity;
gaugeTemp.value = temp;
gaugeHum.value = hum;
}
};
xhr.open("GET", "/readings", true);
xhr.send();
}
if (!!window.EventSource) {
var source = new EventSource('/events');
source.addEventListener('open', function(e) {
console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
if (e.target.readyState != EventSource.OPEN) {
console.log("Events Disconnected");
}
}, false);
source.addEventListener('message', function(e) {
console.log("message", e.data);
}, false);
source.addEventListener('new_readings', function(e) {
console.log("new_readings", e.data);
var myObj = JSON.parse(e.data);
console.log(myObj);
gaugeTemp.value = myObj.temperature;
gaugeHum.value = myObj.humidity;
}, false);
}
Вот краткое описание того, что делает этот код:
инициализация протокола event source;
добавление слушателя событий для события new_readings;
создание шкал;
получение последних показаний датчиков из события new_readings и их отображение на соответствующих шкалах;
выполнение HTTP GET запроса для получения текущих показаний датчиков при первом открытии веб-страницы.
Получение показаний
Когда вы впервые заходите на веб-страницу, мы запрашиваем у сервера текущие показания датчиков. В противном случае нам пришлось бы ждать поступления новых показаний датчиков (через Server-Sent Events), что может занять некоторое время в зависимости от интервала, установленного на сервере.
Добавьте слушатель событий, который вызывает функцию getReadings при загрузке веб-страницы.
// Get current sensor readings when the page loads
window.addEventListener('load', getReadings);
Объект window представляет открытое окно в браузере. Метод addEventListener() настраивает функцию, которая будет вызываться при наступлении определённого события. В данном случае мы вызовем функцию getReadings при загрузке страницы („load“), чтобы получить текущие показания датчиков.
Теперь давайте рассмотрим функцию getReadings. Создайте новый объект XMLHttpRequest. Затем отправьте GET-запрос на сервер по URL /readings, используя методы open() и send().
function getReadings() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/readings", true);
xhr.send();
}
Когда мы отправляем этот запрос, ESP отправит ответ с необходимой информацией. Поэтому нам нужно обработать, что происходит, когда мы получаем ответ. Мы будем использовать свойство onreadystatechange, которое определяет функцию, выполняемую при изменении свойства readyState. Свойство readyState содержит статус XMLHttpRequest. Ответ на запрос готов, когда readyState равен 4, а status равен 200.
readyState = 4 означает, что запрос завершён и ответ готов;
status = 200 означает «OK»
Таким образом, запрос должен выглядеть примерно так:
function getStates(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
... ДЕЛАЙТЕ ВСЁ, ЧТО ХОТИТЕ, С ОТВЕТОМ ...
}
};
xhr.open("GET", "/states", true);
xhr.send();
}
Ответ, отправленный ESP, представляет собой следующий текст в формате JSON (это просто произвольные значения).
{
"temperature" : "25.02",
"humidity" : "64.01",
}
Нам нужно преобразовать строку JSON в объект JSON с помощью метода parse(). Результат сохраняется в переменной myObj.
var myObj = JSON.parse(this.responseText);
Переменная myObj — это JSON-объект, содержащий показания температуры и влажности. Мы хотим обновить значения шкал соответствующими показаниями.
Обновление значения шкалы выполняется просто. Например, наша шкала температуры называется gaugeTemp (как мы увидим далее), чтобы обновить значение, мы можем просто вызвать: gaugeTemp.value = NEW_VALUE. В нашем случае новое значение — это показание температуры, сохранённое в JSON-объекте myObj.
gaugeTemp.value = myObj.temperature;
Аналогично для влажности (наша шкала влажности называется gaugeHum).
gaugeHum.value = myObj.humidity;
Вот полная функция getReadings().
function getReadings(){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var myObj = JSON.parse(this.responseText);
console.log(myObj);
var temp = myObj.temperature;
var hum = myObj.humidity;
gaugeTemp.value = temp;
gaugeHum.value = hum;
}
};
xhr.open("GET", "/readings", true);
xhr.send();
}
Создание шкал
Библиотека canvas-charts позволяет создавать линейные и радиальные шкалы для отображения ваших показаний. Она предоставляет множество примеров и очень проста в использовании. Мы рекомендуем ознакомиться с документацией и изучить все возможности шкал:
Шкала температуры
Следующие строки создают шкалу для отображения температуры.
// Create Temperature Gauge
var gaugeTemp = new LinearGauge({
renderTo: 'gauge-temperature',
width: 120,
height: 400,
units: "Temperature C",
minValue: 0,
startAngle: 90,
ticksAngle: 180,
maxValue: 40,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueDec: 2,
valueInt: 2,
majorTicks: [
"0",
"5",
"10",
"15",
"20",
"25",
"30",
"35",
"40"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 30,
"to": 40,
"color": "rgba(200, 50, 50, .75)"
}
],
colorPlate: "#fff",
colorBarProgress: "#CC2936",
colorBarProgressEnd: "#049faa",
borderShadowWidth: 0,
borders: false,
needleType: "arrow",
needleWidth: 2,
needleCircleSize: 7,
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear",
barWidth: 10,
}).draw();
Для создания новой линейной шкалы используйте метод new LinearGauge() и передайте в качестве аргумента свойства шкалы.
var gaugeTemp = new LinearGauge({
В следующей строке определите, где вы хотите разместить диаграмму (это должен быть элемент <canvas>). В нашем примере мы хотим разместить её в HTML-элементе <canvas> с идентификатором gauge-temperature — см. раздел HTML-файл.
renderTo: 'gauge-temperature',
Затем мы определяем другие свойства для настройки нашей шкалы. Названия говорят сами за себя, но мы рекомендуем ознакомиться со всеми возможными конфигурациями и изменить шкалу в соответствии с вашими потребностями.
В конце вам нужно применить метод draw(), чтобы фактически отобразить шкалу на холсте.
}).draw();
Обратите особое внимание: если вам нужно изменить диапазон шкалы, вам необходимо изменить свойства minValue и maxValue:
minValue: 0,
maxValue: 40,
Вам также нужно скорректировать значения majorTicks для значений, отображаемых на оси.
majorTicks: [
"0",
"5",
"10",
"15",
"20",
"25",
"30",
"35",
"40"
],
Шкала влажности
Создание шкалы влажности аналогично, но мы используем функцию new RadialGauge() вместо этого, и она отрисовывается в элементе <canvas> с идентификатором gauge-humidity. Обратите внимание, что мы применяем метод draw() к шкале, чтобы она была нарисована на холсте.
// Create Humidity Gauge
var gaugeHum = new RadialGauge({
renderTo: 'gauge-humidity',
width: 300,
height: 300,
units: "Humidity (%)",
minValue: 0,
maxValue: 100,
colorValueBoxRect: "#049faa",
colorValueBoxRectEnd: "#049faa",
colorValueBoxBackground: "#f1fbfc",
valueInt: 2,
majorTicks: [
"0",
"20",
"40",
"60",
"80",
"100"
],
minorTicks: 4,
strokeTicks: true,
highlights: [
{
"from": 80,
"to": 100,
"color": "#03C0C1"
}
],
colorPlate: "#fff",
borderShadowWidth: 0,
borders: false,
needleType: "line",
colorNeedle: "#007F80",
colorNeedleEnd: "#007F80",
needleWidth: 2,
needleCircleSize: 3,
colorNeedleCircleOuter: "#007F80",
needleCircleOuter: true,
needleCircleInner: false,
animationDuration: 1500,
animationRule: "linear"
}).draw();
Обработка событий
Обновляйте показания на шкале, когда клиент получает показания при событии new_readings.
Создайте новый объект EventSource и укажите URL страницы, отправляющей обновления. В нашем случае это /events.
if (!!window.EventSource) {
var source = new EventSource('/events');
После того как вы создали экземпляр event source, вы можете начать прослушивание сообщений от сервера с помощью addEventListener().
Это стандартные слушатели событий, как показано в документации AsyncWebServer.
source.addEventListener('open', function(e) {
console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
if (e.target.readyState != EventSource.OPEN) {
console.log("Events Disconnected");
}
}, false);
source.addEventListener('message', function(e) {
console.log("message", e.data);
}, false);
Затем добавьте слушатель событий для new_readings.
source.addEventListener('new_readings', function(e) {
Когда новые показания доступны, ESP8266 отправляет событие (new_readings) клиенту. Следующие строки обрабатывают, что происходит, когда браузер получает это событие.
source.addEventListener('new_readings', function(e) {
console.log("new_readings", e.data);
var myObj = JSON.parse(e.data);
console.log(myObj);
gaugeTemp.value = myObj.temperature;
gaugeHum.value = myObj.humidity;
}, false);
По сути, он выводит новые показания в консоль браузера, преобразует данные в JSON-объект и отображает показания на соответствующих шкалах.
Скетч Arduino
Скопируйте следующий код в Arduino IDE или в файл main.cpp, если вы используете PlatformIO.
Вы также можете скачать все файлы здесь.
/*********
Rui Santos
Complete instructions at https://RandomNerdTutorials.com/esp8266-web-server-gauges/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "LittleFS.h"
#include <Arduino_JSON.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Create an Event Source on /events
AsyncEventSource events("/events");
// Json Variable to Hold Sensor Readings
JSONVar readings;
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
// Create a sensor object
Adafruit_BME280 bme; // BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)
// Init BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}
// Get Sensor Readings and return JSON object
String getSensorReadings(){
readings["temperature"] = String(bme.readTemperature());
readings["humidity"] = String(bme.readHumidity());
String jsonString = JSON.stringify(readings);
return jsonString;
}
// Initialize LittleFS
void initFS() {
if (!LittleFS.begin()) {
Serial.println("An error has occurred while mounting LittleFS");
}
Serial.println("LittleFS mounted successfully");
}
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initBME();
initWiFi();
initFS();
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
server.serveStatic("/", LittleFS, "/");
// Request for the latest sensor readings
server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
String json = getSensorReadings();
request->send(200, "application/json", json);
json = String();
});
events.onConnect([](AsyncEventSourceClient *client){
if(client->lastId()){
Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
}
// send event with message "hello!", id current millis
// and set reconnect delay to 1 second
client->send("hello!", NULL, millis(), 10000);
});
server.addHandler(&events);
// Start server
server.begin();
}
void loop() {
if ((millis() - lastTime) > timerDelay) {
// Send Events to the client with the Sensor Readings Every 30 seconds
events.send("ping",NULL,millis());
events.send(getSensorReadings().c_str(),"new_readings" ,millis());
lastTime = millis();
}
}
Как работает код
Давайте рассмотрим код и посмотрим, как он работает для отправки показаний клиенту с помощью server-sent events.
Подключение библиотек
Библиотеки Adafruit_Sensor и Adafruit_BME280 необходимы для взаимодействия с датчиком BME280.
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
Библиотеки ESP8266WiFi, ESPAsyncWebServer и ESPAsyncTCP используются для создания веб-сервера.
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
Мы будем использовать LittleFS для сохранения файлов для построения веб-сервера.
#include "LittleFS.h"
Вам также необходимо подключить библиотеку Arduino_JSON, чтобы упростить работу с JSON-строками.
#include <Arduino_JSON.h>
Сетевые учётные данные
Вставьте свои сетевые учётные данные в следующие переменные, чтобы ESP8266 мог подключиться к вашей локальной сети по Wi-Fi.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
AsyncWebServer и AsyncEventSource
Создайте объект AsyncWebServer на порту 80.
AsyncWebServer server(80);
Следующая строка создаёт новый источник событий на /events.
AsyncEventSource events("/events");
Объявление переменных
Переменная readings — это JSON-переменная для хранения показаний датчиков в формате JSON.
JSONVar readings;
Переменные lastTime и timerDelay будут использоваться для обновления показаний датчиков каждые X секунд. В качестве примера мы будем получать новые показания датчиков каждые 30 секунд (30000 миллисекунд). Вы можете изменить это время задержки в переменной timerDelay.
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
Создайте объект Adafruit_BME280 с именем bme на стандартных выводах I2C ESP.
Adafruit_BME280 bme;
Инициализация датчика BME280
Следующая функция может быть вызвана для инициализации датчика BME280.
// Init BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}
Получение показаний BME280
Для получения температуры и влажности с датчика BME280 используйте следующие методы объекта bme:
bme.readTemperature()
bme.readHumidity()
Функция getSensorReadings() получает показания датчиков и сохраняет их в JSON-массиве readings.
// Get Sensor Readings and return JSON object
String getSensorReadings(){
readings["temperature"] = String(bme.readTemperature());
readings["humidity"] = String(bme.readHumidity());
String jsonString = JSON.stringify(readings);
return jsonString;
}
Затем массив readings преобразуется в JSON-строку с помощью метода stringify() и сохраняется в переменной jsonString.
Функция возвращает переменную jsonString с текущими показаниями датчиков. JSON-строка имеет следующий формат (значения являются произвольными числами для пояснения).
{
"temperature" : "25",
"humidity" : "50"
}
setup()
В setup() инициализируйте Serial Monitor, Wi-Fi, файловую систему и датчик BME280.
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
initBME();
initWiFi();
initFS();
Обработка запросов
Когда вы обращаетесь к IP-адресу ESP8266 по корневому URL /, отправляется текст, сохранённый в файле index.html, для построения веб-страницы.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
Обслуживание других статических файлов, запрошенных клиентом (style.css и script.js).
server.serveStatic("/", LittleFS, "/");
Отправка JSON-строки с текущими показаниями датчиков при получении запроса по URL /readings.
// Request for the latest sensor readings
server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
String json = getSensorReadings();
request->send(200, "application/json", json);
json = String();
});
Переменная json содержит результат функции getSensorReadings(). Для отправки JSON-строки в качестве ответа метод send() принимает первым аргументом код ответа (200), вторым — тип содержимого («application/json») и, наконец, само содержимое (переменная json).
Источник событий сервера
Настройте источник событий на сервере.
events.onConnect([](AsyncEventSourceClient *client){
if(client->lastId()){
Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
}
// send event with message "hello!", id current millis
// and set reconnect delay to 1 second
client->send("hello!", NULL, millis(), 10000);
});
server.addHandler(&events);
Наконец, запустите сервер.
server.begin();
loop()
В loop() отправляйте события в браузер с новейшими показаниями датчиков для обновления веб-страницы каждые 30 секунд.
events.send("ping",NULL,millis());
events.send(getSensorReadings().c_str(),"new_readings" ,millis());
Используйте метод send() объекта events и передайте в качестве аргумента содержимое, которое вы хотите отправить, и имя события. В данном случае мы хотим отправить JSON-строку, возвращаемую функцией getSensorReadings(). Метод send() принимает переменную типа char, поэтому нам нужно использовать метод c_str() для преобразования переменной. Имя событий — new_readings.
Обычно мы также отправляем ping-сообщение каждые X секунд. Эта строка не является обязательной. Она используется для проверки на стороне клиента, что сервер работает.
events.send("ping",NULL,millis());
Загрузка кода и файлов
После ввода ваших сетевых учётных данных сохраните код. Перейдите в Sketch > Show Sketch Folder и создайте папку с именем data.
Внутри этой папки вы должны сохранить файлы HTML, CSS и JavaScript.
Затем загрузите код на вашу плату ESP8266. Убедитесь, что вы выбрали правильную плату и COM-порт. Также убедитесь, что вы добавили свои сетевые учётные данные.
После загрузки кода вам необходимо загрузить файлы в файловую систему.
Нажмите [ Ctrl] + [ Shift] + [ P] на Windows или [ Cmd] + [ Shift] + [ P] на MacOS, чтобы открыть палитру команд. Найдите команду Upload LittleFS to Pico/ESP8266/ESP32 и нажмите на неё.
Если у вас нет этой опции, значит вы не установили плагин загрузки файловой системы. Ознакомьтесь с этим руководством.
Когда всё будет успешно загружено, откройте Serial Monitor с скоростью передачи данных 115200. Нажмите кнопку EN/RST на ESP8266, и он должен вывести IP-адрес ESP8266.
Демонстрация
Откройте браузер и введите IP-адрес ESP8266. Вы должны получить доступ к веб-странице, отображающей шкалы с последними показаниями датчиков.
Вы также можете проверить свои шкалы с помощью смартфона (веб-страница адаптивна для мобильных устройств).
Заключение
В этом руководстве вы узнали, как создать веб-сервер для отображения показаний датчиков на линейных и радиальных шкалах. В качестве примера мы отображали температуру и влажность с датчика BME280. Вы можете использовать эти шкалы для отображения любых других значений, которые могут быть полезны для вашего проекта.
Вам также может быть интересно прочитать:
Узнайте больше о ESP8266 с нашими ресурсами:
Спасибо за чтение.