Взаимодействие ESP8266 NodeMCU с датчиками температуры и влажности DHT11 и DHT22 и вывод показаний, используя веб-сервер
Вы когда-нибудь хотели, чтобы датчики были разбросаны по всему вашему дому и саду, регулярно сообщая о своей температуре центральному серверу? Тогда этот IoT проект может стать для вас хорошей отправной точкой! Данный проект использует ESP8266 NodeMCU в качестве управляющего устройства, которое легко подключается к существующей сети Wi-Fi и создает веб-сервер. Когда какое-либо подключенное устройство получает доступ к этому веб-серверу, ESP8266 NodeMCU считывает температуру и относительную влажность с датчика DHT11, DHT22/AM2302 и отправляет его в красивом виде в веб-браузер этого устройства. Интересно? Давайте начнем!
Это может показаться пугающим, но прежде чем углубляться в данное руководство, есть несколько концепций, с которыми вы должны быть знакомы. Если какое-либо из представленных ниже понятий звучит для вас незнакомо, попробуйте сначала прочитать (хотя бы вскользь) следующие статьи:
- Как работают датчики температуры и влажности DHT11 и DHT22, и их взаимодействие с Arduino
- Обзор платы NodeMCU ESP8266 и ее использование в Arduino IDE
- Создание простого веб-сервера на ESP8266 NodeMCU в Arduino IDE
Подключение датчика DHT11, DHT22/AM2302 к плате ESP8266 NodeMCU
Подключить датчик DHT11/DHT22/AM2302 к ESP8266 NodeMCU довольно просто. Начните с установки NodeMCU на макетную плату, чтобы каждая сторона платы NodeMCU была на отдельной стороне макетной платы.
Теперь установите датчик на макетную плату, в стороне от NodeMCU. Подключите вывод VCC датчика к выводу 3,3V на NodeMCU и соедините выводы земли датчика и платы. Также подключите вывод данных датчика к выводу D8 платы ESP8266 NodeMCU. Наконец, нам нужно установить подтягивающий резистор 10 кОм между линией VCC и линией данных, чтобы на ней поддерживался высокий логический уровень для корректной связи между датчиком и NodeMCU. Если у вас датчик установлен на отдельную плату, возможно, вам не нужно добавлять какие-либо внешние подтягивающие резисторы. В этом случае датчик поставляется уже со встроенным подтягивающим резистором.
Когда вы закончите, у вас должно получиться что-то похожее на рисунок ниже.
Установка библиотеки датчиков DHT
Связь с датчиками DHT11, с датчиками DHT22/AM2302 – это сложная задача, поскольку для передачи данных они используют собственный однопроводный протокол. Этот протокол требует точной синхронизации. К счастью, нам не нужно беспокоиться об этом, потому что мы собираемся использовать библиотеку DHT от Adafruit, которая позаботится почти обо всем. Эта библиотека настолько мощна, что работает как на архитектуре Arduino, так и на архитектуре ESP.
Чтобы установить библиотеку, перейдите в меню Скетч (Sketch) → Подключить библиотеку (Include Library) → Управлять библиотеками… (Manage Libraries...). Подождите, пока менеджер библиотек загрузит индекс библиотек и обновит список установленных библиотек.
Отфильтруйте результаты поиска, введя «DHT sensor». Должна остаться пара записей. Найдите DHT sensor library by Adafruit. Нажмите на эту запись, а затем выберите Установить (Install).
Библиотека датчиков DHT использует Adafruit Sensor support backend. Поэтому поищите в менеджере библиотек Adafruit Unified Sensor и установите его тоже (возможно, придется немного прокрутить).
Создание веб-сервера NodeMCU ESP8266, используя Wi-Fi режим Station (STA)
Теперь перейдем к более интересному!
Как следует из заголовка, мы собираемся настроить наш ESP8266 NodeMCU в режим Station (STA) и создать веб-сервер для выдачи веб-страниц любому подключенному к существующей сети клиенту.
Прежде чем приступить к загрузке скетча, чтобы он у вас заработал, необходимо внести одно изменение. Чтобы ESP8266 NodeMCU мог установить соединение с существующей сетью, вам необходимо изменить следующие две переменные в соответствии с учетными данными вашей сети.
/* Установите здесь свои SSID и пароль */
const char* ssid = "YourNetworkName"; // SSID
const char* password = "YourPassword"; // пароль
Как только вы это сделаете, попробуйте загрузить скетч, и мы рассмотрим его подробнее.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "DHT.h"
// Раскомментируйте одну из строк ниже в зависимости от того, какой датчик вы используете!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
/* Введите свои SSID и пароль */
const char* ssid = "YourNetworkName"; // SSID
const char* password = "YourPassword"; // пароль
ESP8266WebServer server(80);
// датчик DHT
uint8_t DHTPin = D8;
// инициализация датчика DHT.
DHT dht(DHTPin, DHTTYPE);
float Temperature;
float Humidity;
void setup()
{
Serial.begin(115200);
delay(100);
pinMode(DHTPin, INPUT);
dht.begin();
Serial.println("Connecting to ");
Serial.println(ssid);
// подключаемся к локальной wi-fi сети
WiFi.begin(ssid, password);
// проверить, подключился ли wi-fi модуль к wi-fi сети
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop()
{
server.handleClient();
}
void handle_OnConnect()
{
Temperature = dht.readTemperature(); // получить значение температуры
Humidity = dht.readHumidity(); // получить значение влажности
server.send(200, "text/html", SendHTML(Temperature,Humidity));
}
void handle_NotFound()
{
server.send(404, "text/plain", "Not found");
}
String SendHTML(float Temperaturestat,float Humiditystat)
{
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP8266 Weather Report</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 NodeMCU Weather Report</h1>\n";
ptr +="<p>Temperature: ";
ptr +=(int)Temperaturestat;
ptr +="°C</p>";
ptr +="<p>Humidity: ";
ptr +=(int)Humiditystat;
ptr +="%</p>";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
Доступ к веб-серверу
После загрузки скетча откройте монитор последовательного порта со скоростью 115200 бит/с и нажмите кнопку RESET на NodeMCU. Если всё в порядке, он выведет динамический IP адрес, полученный от вашего маршрутизатора, и покажет сообщение о том, что HTTP сервер запущен.
Затем загрузите браузер и введите IP адрес, указанный в мониторе последовательного порта. ESP8266 NodeMCU должен выдать веб-страницу, показывающую температуру и относительную влажность.
Подробное объяснение кода
Скетч начинается с включения библиотеки ESP8266WiFi.h. Эта библиотека предоставляет специальные методы ESP8266 NodeMCU для работы с Wi-Fi, которые мы вызываем для подключения к сети. После этого мы также включили библиотеку ESP8266WebServer.h, в которой есть несколько методов, которые помогут нам настроить сервер и обрабатывать входящие HTTP запросы, не беспокоясь о деталях низкоуровневой реализации. И, наконец, мы включаем библиотеку DHT.h.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "DHT.h"
Далее нам нужно определить тип используемого датчика DHT. Раскомментируйте одну из строк ниже!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
Поскольку мы настраиваем ESP8266 NodeMCU в режиме станции (STA), он подключится к существующей сети Wi-Fi. Следовательно, нам необходимо предоставить SSID и пароль вашей сети.
const char* ssid = "YourNetworkName"; // SSID
const char* password = "YourPassword"; // пароль
Далее мы объявляем объект библиотеки ESP8266WebServer
, чтобы получить доступ к ее функциям. Конструктор этого объекта в качестве параметра принимает номер порта (который сервер будет прослушивать). Так как 80 – это порт по умолчанию для HTTP, мы будем использовать это значение. Теперь вы можете получить доступ к серверу, не указывая порт в URL.
ESP8266WebServer server(80);
Затем нам нужно определить номер вывода ESP8266 NodeMCU, к которому подключен вывод данных датчика, и создать объект DHT, чтобы было можно получить доступ к специальным функциям, связанным с библиотекой DHT.
// датчик DHT
uint8_t DHTPin = D8;
// инициализация датчика DHT.
DHT dht(DHTPin, DHTTYPE);
Две переменные типа float
, а именно Temperature
и Humidity
объявляются для хранения значений соответственно температуры и влажности.
float Temperature;
float Humidity;
Внутренности функции setup()
Перед запуском настраиваем HTTP сервер. Прежде всего, для отладки открываем последовательное соединение и устанавливаем порты GPIO на вход. Также нам нужно инициализировать объект DHT с помощью функции begin()
.
Serial.begin(115200);
delay(100);
pinMode(DHTPin, INPUT);
dht.begin();
Теперь нам нужно подключиться к сети Wi-Fi с помощью функции WiFi.begin()
. Данная функция принимает в качестве параметров SSID (имя сети) и пароль.
Serial.println("Connecting to ");
Serial.println(ssid);
// подключаемся к локальной wi-fi сети
WiFi.begin(ssid, password);
Пока ESP8266 пытается подключиться к сети, мы проверяем состояние подключения с помощью функции WiFi.status()
.
// проверить, подключился ли wi-fi модуль к wi-fi сети
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Как только ESP8266 будет подключен к сети, скетч печатает IP адрес, присвоенный для ESP8266, отображая значение WiFi.localIP()
в мониторе последовательного порта.
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
Чтобы обрабатывать входящие HTTP запросы, нам нужно указать, какой код выполнять при введении определенного URL. Для этого мы используем метод on()
. Этот метод принимает два параметра. Первый – это URL путь, а второй – имя функции, которую мы хотим выполнить при входе на этот URL.
Приведенный ниже код указывает, что когда сервер получает HTTP запрос по корневому пути (/), он запускает функцию handle_OnConnect()
. Обратите внимание, что указанный URL адрес представляет собой относительный путь.
server.on("/", handle_OnConnect);
Мы не указали, что должен делать сервер, если клиент запрашивает какой-либо URL, отличающийся от указанных в server.on()
. Он должен выдать ответ с HTTP статусом 404 (Not Found, «страница не найдена») и сообщением для пользователя. Помещаем эти действия в отдельную функцию и используем метод server.onNotFound()
, чтобы указать серверу, что он должен выполнить, когда получит запрос на URI, который не был задан с помощью server.on()
.
server.onNotFound(handle_NotFound);
Теперь, чтобы запустить сервер, вызываем метод begin()
для объекта server
.
server.begin();
Serial.println("HTTP server started");
Внутренности функции loop()
Чтобы обработать реальные входящие HTTP запросы, нам нужно вызвать метод handleClient()
объекта server
.
server.handleClient();
Далее нам нужно создать функцию, которую мы прикрепили к корневому (/) URL с помощью server.on()
. Помните? В начале этой функции мы получаем от датчика значения температуры и влажности. Чтобы ответить на HTTP запрос, используем метод send()
. Хотя этот метод можно вызывать с другим набором аргументов, его самая простая форма состоит из HTTP кода ответа, типа контента и самого контента.
В нашем случае мы отправляем код 200 (один из кодов состояния HTTP), который соответствует ответу OK. Затем мы указываем тип контента как "text/html", и, наконец, мы вызываем пользовательскую функцию SendHTML()
, которая создает динамическую HTML страницу, содержащую значения температуры и влажности.
void handle_OnConnect()
{
Temperature = dht.readTemperature(); // получить значение температуры
Humidity = dht.readHumidity(); // получить значение влажности
server.send(200, "text/html", SendHTML(Temperature,Humidity));
}
Точно так же нам нужно создать функцию для обработки страницы ошибки 404.
void handle_NotFound()
{
server.send(404, "text/plain", "Not found");
}
Отображение веб-страницы HTML
Функция SendHTML()
отвечает за создание веб-страницы всякий раз, когда веб-сервер ESP8266 получает запрос от веб-клиента. Она просто объединяет HTML код в большую строку и возвращает ее в функцию server.send()
, которую мы обсуждали ранее. Данная функция в качестве параметров для динамического генерирования HTML контента принимает значения температуры и влажности.
Первый текст, который вы всегда должны отправлять, - это объявление <!DOCTYPE>
, которое указывает, что мы отправляем HTML код.
String SendHTML(float Temperaturestat,float Humiditystat)
{
String ptr = "<!DOCTYPE html> <html>\n";
Затем <meta>
элемент viewport
делает веб-страницу адаптивной в любом веб-браузере. Далее тег title
устанавливает заголовок страницы.
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP8266 Weather Report</title>\n";
Стилизация веб-страницы
Далее идет немного CSS кода для стилизации внешнего вида веб-страницы. Мы выбираем шрифт Helvetica, определяем контент, который будет отображаться в виде inline-block и выровнен по центру.
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
Следующий код устанавливает цвет, шрифт и поля вокруг элементов body
, H1
, H3
и p
.
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
Установка заголовка веб-страницы
Далее устанавливаем заголовок на веб-странице; вы можете изменить этот текст на то, что подходит для вашего приложения.
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 Weather Report</h1>\n";
Отображение температуры и влажности на веб-странице
Чтобы динамически отображать значения температуры и влажности, мы помещаем эти значения в тег параграфа. Эти значения преобразуются в целое число с помощью приведения типов. Для отображения символа градуса мы используем HTML сущность °
.
Стилизация веб-страницы, чтобы она выглядела более профессионально
Программисты, подобные нам, часто боятся дизайна – но небольшое усилие может сделать вашу веб-страницу более привлекательной и профессиональной. Скриншот, приведенный ниже, даст вам базовое представление о том, что мы собираемся делать.
Довольно красиво, правда? Давайте без лишних слов, применим стиль к нашей предыдущей HTML странице. Для начала скопируйте и вставьте приведенный ниже код, чтобы заменить в приведенном выше скетче функцию SendHTML()
. Попробуйте новый скетч, а затем мы выполним его детальный разбор.
String SendHTML(float TempCstat,float TempFstat,float Humiditystat)
{
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600\" rel=\"stylesheet\">\n";
ptr +="<title>ESP8266 Weather Report</title>\n";
ptr +="<style>html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #333333;}\n";
ptr +="body{margin-top: 50px;}\n";
ptr +="h1 {margin: 50px auto 30px;}\n";
ptr +=".side-by-side{display: inline-block;vertical-align: middle;position: relative;}\n";
ptr +=".humidity-icon{background-color: #3498db;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
ptr +=".humidity-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".humidity{font-weight: 300;font-size: 60px;color: #3498db;}\n";
ptr +=".temperature-icon{background-color: #f39c12;width: 30px;height: 30px;border-radius: 50%;line-height: 40px;}\n";
ptr +=".temperature-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".temperature{font-weight: 300;font-size: 60px;color: #f39c12;}\n";
ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -20px;top: 15px;}\n";
ptr +=".data{padding: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 Weather Report</h1>\n";
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side temperature-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n";
ptr +="width=\"9.915px\" height=\"22px\" viewBox=\"0 0 9.915 22\" enable-background=\"new 0 0 9.915 22\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M3.498,0.53c0.377-0.331,0.877-0.501,1.374-0.527C5.697-0.04,6.522,0.421,6.924,1.142\n";
ptr +="c0.237,0.399,0.315,0.871,0.311,1.33C7.229,5.856,7.245,9.24,7.227,12.625c1.019,0.539,1.855,1.424,2.301,2.491\n";
ptr +="c0.491,1.163,0.518,2.514,0.062,3.693c-0.414,1.102-1.24,2.038-2.276,2.594c-1.056,0.583-2.331,0.743-3.501,0.463\n";
ptr +="c-1.417-0.323-2.659-1.314-3.3-2.617C0.014,18.26-0.115,17.104,0.1,16.022c0.296-1.443,1.274-2.717,2.58-3.394\n";
ptr +="c0.013-3.44,0-6.881,0.007-10.322C2.674,1.634,2.974,0.955,3.498,0.53z\"/>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side temperature-text\">Temperature</div>\n";
ptr +="<div class=\"side-by-side temperature\">";
ptr +=(int)TempCstat;
ptr +="<span class=\"superscript\">°C</span></div>\n";
ptr +="</div>\n";
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side humidity-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_2\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\"; width=\"12px\" height=\"17.955px\" viewBox=\"0 0 13 17.955\" enable-background=\"new 0 0 13 17.955\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M1.819,6.217C3.139,4.064,6.5,0,6.5,0s3.363,4.064,4.681,6.217c1.793,2.926,2.133,5.05,1.571,7.057\n";
ptr +="c-0.438,1.574-2.264,4.681-6.252,4.681c-3.988,0-5.813-3.107-6.252-4.681C-0.313,11.267,0.026,9.143,1.819,6.217\"></path>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side humidity-text\">Humidity</div>\n";
ptr +="<div class=\"side-by-side humidity\">";
ptr +=(int)Humiditystat;
ptr +="<span class=\"superscript\">%</span></div>\n";
ptr +="</div>\n";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
Мы уже знаем, что объявление <!DOCTYPE>
сообщает браузеру, что мы отправляем HTML код, а <meta>
элемент viewport
делает веб-страницу адаптивной. Единственное дополнение здесь заключается в том, что мы будем использовать шрифты google. Google имеет сотни веб-шрифтов и бесплатен для коммерческого и личного использования. Прекрасно!
На нашей веб-странице мы будем использовать шрифт Open Sans. Шрифт Google встраивается с помощью тега link
в блоке <head>
HTML документа. Для нашей страницы мы выбрали следующие веса (толщину) шрифта: 300 (легкий), 400 (обычный) и 600 (жирный). Вы можете выбрать столько, сколько захотите, но имейте в виду, что выбор ненужных весов шрифтов затрудняет загрузку страницы. Вы также можете добавить курсивный стиль, просто добавив символ i
в конце веса шрифта, например, 400i встроит курсивный стиль.
Обратите внимание, что вы не можете видеть шрифт Google, без активного подключения к интернету на устройстве, с которого вы собираетесь получить доступ к странице. Шрифты Google загружаются на лету.
String SendHTML(float TempCstat,float TempFstat,float Humiditystat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600\" rel=\"stylesheet\">\n";
Далее мы собираемся применить шрифт "Open Sans" для всего нашего HTML кода. Мы также должны указать sans-serif в качестве нашего резервного шрифта, чтобы обеспечить максимальную совместимость между браузерами/операционными системами. Если браузер не поддерживает первый шрифт, он попытается использовать следующий шрифт.
ptr +="<title>ESP8266 Weather Report</title>\n";
ptr +="<style>html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #333333;}\n";
ptr +="body{margin-top: 50px;}\n";
ptr +="h1 {margin: 50px auto 30px;}\n";
Далее нам нужно применить CSS для иконок, заголовков и фактических значений влажности и температуры. Все эти три вещи сделаны строчными и выровнены по вертикали. Фон иконок выполнен круглым с помощью 50% радиуса границы и сделан 30px высотой и шириной.
ptr +=".side-by-side{display: inline-block;vertical-align: middle;position: relative;}\n";
ptr +=".humidity-icon{background-color: #3498db;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
ptr +=".humidity-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".humidity{font-weight: 300;font-size: 60px;color: #3498db;}\n";
ptr +=".temperature-icon{background-color: #f39c12;width: 30px;height: 30px;border-radius: 50%;line-height: 40px;}\n";
ptr +=".temperature-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".temperature{font-weight: 300;font-size: 60px;color: #f39c12;}\n";
ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -20px;top: 15px;}\n";
ptr +=".data{padding: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
Затем мы покажем показания температуры с помощью этого красивого маленького значка .
Значок температуры на самом деле является масштабируемой векторной графикой (SVG), определенной в теге <svg>
. Создание SVG не требует каких-либо специальных навыков программирования. Для создания графики для вашей страницы вы можете использовать любой редактор SVG. После этой иконки мы собираемся показать фактическое значение температуры датчика.
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 NodeMCU Weather Report</h1>\n";
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side temperature-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n";
ptr +="width=\"9.915px\" height=\"22px\" viewBox=\"0 0 9.915 22\" enable-background=\"new 0 0 9.915 22\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M3.498,0.53c0.377-0.331,0.877-0.501,1.374-0.527C5.697-0.04,6.522,0.421,6.924,1.142\n";
ptr +="c0.237,0.399,0.315,0.871,0.311,1.33C7.229,5.856,7.245,9.24,7.227,12.625c1.019,0.539,1.855,1.424,2.301,2.491\n";
ptr +="c0.491,1.163,0.518,2.514,0.062,3.693c-0.414,1.102-1.24,2.038-2.276,2.594c-1.056,0.583-2.331,0.743-3.501,0.463\n";
ptr +="c-1.417-0.323-2.659-1.314-3.3-2.617C0.014,18.26-0.115,17.104,0.1,16.022c0.296-1.443,1.274-2.717,2.58-3.394\n";
ptr +="c0.013-3.44,0-6.881,0.007-10.322C2.674,1.634,2.974,0.955,3.498,0.53z\"/>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side temperature-text\">Temperature</div>\n";
ptr +="<div class=\"side-by-side temperature\">";
ptr +=(int)TempCstat;
ptr +="<span class=\"superscript\">°C</span></div>\n";
ptr +="</div>\n";
Далее мы покажем показания влажности с помощью этого значка .
Опять же это SVG. После печати значений влажности мы закрываем все открытые теги, такие как body
и html
.
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side humidity-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_2\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\"; width=\"12px\" height=\"17.955px\" viewBox=\"0 0 13 17.955\" enable-background=\"new 0 0 13 17.955\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M1.819,6.217C3.139,4.064,6.5,0,6.5,0s3.363,4.064,4.681,6.217c1.793,2.926,2.133,5.05,1.571,7.057\n";
ptr +="c-0.438,1.574-2.264,4.681-6.252,4.681c-3.988,0-5.813-3.107-6.252-4.681C-0.313,11.267,0.026,9.143,1.819,6.217\"></path>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side humidity-text\">Humidity</div>\n";
ptr +="<div class=\"side-by-side humidity\">";
ptr +=(int)Humiditystat;
ptr +="<span class=\"superscript\">%</span></div>\n";
ptr +="</div>\n";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
Улучшение кода – автоматическое обновление страницы
Одно из улучшений, которое вы можете сделать с нашим кодом, – это автоматическое обновление страницы для обновления показаний датчика.
Добавив один мета-тег в ваш HTML документ, вы можете дать браузеру команду автоматически перезагружать страницу с заданным интервалом.
<meta http-equiv="refresh" content="2" >
Поместите этот код в тег <head>
вашего документа, и этот мета-тег укажет браузеру обновлять страницу каждые две секунды. Довольно изящно!
Динамическая загрузка данных датчика с помощью AJAX
Если ваша веб-страница много весит, то полное ее обновление не слишком практично. Лучше использовать асинхронный Javascript и Xml (AJAX), чтобы мы могли запрашивать данные с сервера асинхронно (в фоновом режиме), не обновляя страницу.
Для выполнения AJAX на веб-страницах в JavaScript обычно используется объект XMLHttpRequest
. Он тихо выполняет GET запрос на сервер и обновляет элемент на странице. AJAX – это не новая технология или другой язык, а просто существующие технологии, используемые по-новому. Кроме того, AJAX также позволяет:
- запрашивать данные с сервера после загрузки страницы;
- получать данные с сервера после загрузки страницы;
- отправлять данные на сервер в фоновом режиме.
Ниже приведен скрипт AJAX, который мы будем использовать. Поместите этот скрипт непосредственно перед закрывающим тегом </head>
.
ptr +="<script>\n";
ptr +="setInterval(loadDoc,200);\n";
ptr +="function loadDoc() {\n";
ptr +="var xhttp = new XMLHttpRequest();\n";
ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.getElementById(\"webpage\").innerHTML =this.responseText}\n";
ptr +="};\n";
ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";
ptr +="</script>\n";
Скрипт начинается с тега <script>
, так как AJAX-скрипт – это не что иное, как javascript, и поэтому нужно писать его в теге <script>
. Чтобы данная функция вызывалась повторно, мы будем использовать функцию javascript setInterval()
. Она принимает два параметра: функцию для выполнения и интервал времени (в миллисекундах), через который выполнять указанную функцию.
ptr +="<script>\n";
ptr +="setInterval(loadDoc,200);\n";
Сердцем этого скрипта является функция loadDoc()
. Внутри этой функции создается объект XMLHttpRequest()
. Данный объект используется для запроса данных с веб-сервера.
ptr +="function loadDoc() {\n";
ptr +="var xhttp = new XMLHttpRequest();\n";
Функция xhttp.onreadystatechange()
вызывается каждый раз, когда изменяется readyState
. Свойство readyState
хранит состояние XMLHttpRequest
. Возможны следующие значения:
- 0: запрос не инициализирован;
- 1: установлено подключение к серверу;
- 2: запрос получен;
- 3: обработка запроса;
- 4: запрос завершен, и ответ готов.
Свойство status
содержит статус объекта XMLHttpRequest
. Возможны следующие значения:
- 200: OK;
- 403: запрещено;
- 404: страница не найдена.
Когда readyState
равен 4, а status
– 200, ответ готов. Теперь обновляется содержимое элемента с id
webpage (div
, содержащей значения температуры и влажности).
ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.getElementById(\"webpage\").innerHTML =this.responseText}\n";
ptr +="};\n";
Затем HTTP запрос инициируется с помощью функций open()
и send()
.
ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";