Вопрос или проблема
Я расширяю пример кода для WiFi-термометра функцией логгирования данных. Статус RTC и SD-карты будет отображаться в HTML-файле. В коде присутствуют заполнители для статуса RTC и SD-карты. Установленный процессор заменяет заполнители значениями, подготовленными MCU.
String statusRTC = "a";
String statusSD = "b";
Определены как глобальные.
Включения:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <Hash.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <Ticker.h>
#include "RTClib.h"
Чистый пример кода работает даже при отсутствии RTC и SD-карты. После добавления секций для RTC и SD соединение истекает. В мониторинге последовательного порта появляется ошибка (28), что означает доступ к недоступному адресу.
Смотрите секцию HTML, процессор, корневую секцию в настройках:
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: left;
padding: 3px;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 2.0rem; }
.dht-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
</head>
<body>
<h2>ESP8266 QDHTD Server</h2>
<h3>RealtimeClocks</h3>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="dht-labels">Температура</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">°C</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Влажность</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units"> pct</sup>
</p>
<!-- добавлено для отображения статуса RTC и SD-карты -->
<p>
<i class="fas fa-clock" style="color:#059e8a;"></i>
<span class="dht-labels">RTC____</span>
<span id="rtc">%STAT_RTC%</span>
</p>
<p>
<i class="fas fa-sd-card" style="color:#059e8a;"></i>
<span class="dht-labels">Память</span>
<span id="sd_card">%STAT_SD%</span>
</p>
</body>
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("rtc").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/rtc", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("sd_card").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/sd_card", true);
xhttp.send();
}, 10000 ) ;
</script>
</html>)rawliteral";
——————————-
Процессор:
// Заменяет заполнители значениями DHT
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return String(t);
}
else if(var == "HUMIDITY"){
return String(h);
}
else if( var == "STAT_RTC"){
if( rtc.isrunning()){
statusRTC = "в порядке.";
return(statusRTC);
}
else {
statusRTC = "не работает";
return(statusRTC);
}
}
else if( var == "STAT_SD"){
bool avail =SD.exists("datalog.txt");
if( avail== true){
statusSD = "в порядке.";
return(statusSD);
}
else {
statusSD = "SD не работает";
return(statusSD);
}
}
return String();
}
———————
Корень в настройках:
// Маршрут для корня / веб-страницы
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(t).c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", String(h).c_str());
});
server.on("/rtc", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", statusRTC.c_str());
});
server.on("/sd_card", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", statusSD.c_str());
});
Поиск в интернете. Проверка на % в заполнительных значениях. Ссылка на HTML. Проверка правильности HTML на w3school
Ответ или решение
Для решения проблемы, с которой вы столкнулись при использовании библиотеки ESPAsyncWebServer
на платформе ESP8266, необходимо учесть несколько ключевых моментов. Вы упомянули, что получаете исключение (28), указывающее на доступ к недопустимому адресу, когда добавляете секции для RTC и SD-карты. Давайте разберемся с возможными решениями этой проблемы.
1. Проверка статуса RTC и SD-карты
Первое, что следует сделать, — убедиться, что устройства RTC и SD-карты корректно инициализированы, и доступ к ним возможен. Это можно сделать в функции setup()
, например:
if (!rtc.begin()) {
Serial.println("RTC не найден");
}
if (!SD.begin()) {
Serial.println("Не удалось инициализировать SD-карту");
}
2. Обновление кода процессора
Ваш код для замены плейсхолдеров в HTML-документе выглядит неплохо. Однако в функции processor
вы не учитываете возможность, что при обращении к ним могут возникнуть ошибки. Также стоит добавить некоторые проверки.
String processor(const String& var) {
if (var == "TEMPERATURE") {
return String(t);
} else if (var == "HUMIDITY") {
return String(h);
} else if (var == "STAT_RTC") {
if (rtc.isrunning()) {
statusRTC = "o.k.";
} else {
statusRTC = "не работает";
}
return statusRTC; // Статус RTC
} else if (var == "STAT_SD") {
bool avail = SD.exists("datalog.txt");
if (avail) {
statusSD = "o.k.";
} else {
statusSD = "Ошибка SD";
}
return statusSD; // Статус SD-карты
}
return String(); // В случае если переменная не совпадает
}
3. Корректное отображение статусов
В вашей HTML-странице отображаются статусы RTC и SD-карты. Убедитесь, что _rtc
и _sd_card
корректно обновляются:
setInterval(function () {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("rtc").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/rtc", true);
xhttp.send();
}, 10000); // 10 секунд для обновления статуса RTC
setInterval(function () {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("sd_card").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/sd_card", true);
xhttp.send();
}, 10000); // 10 секунд для обновления статуса SD-карты
4. Настройка маршрутов
Убедитесь, что маршруты настроены правильно и что они вызываются. Ваш код маршрутов выглядит хорошо, но добавьте проверки ошибок, если необходимо. Например, можно добавлять логгирование на сериал монитор для каждой из команд.
5. Дополнительные рекомендации
- Убедитесь, что все библиотеки обновлены до последних версий, так как их стабильность может оказать влияние на функциональность.
- Также проверьте настройки вашей сети и наличие других компонентов, которые могут вызывать помехи.
- Не забывайте об управлении памятью. Поскольку вы используете массивы строк, следите за их длиной и объемом используемой памяти.
Следуя данным рекомендациям, вы сможете устранить проблему с обращением к недопустимым адресам и предоставить корректную информацию о статусах RTC и SD-карты на вашем веб-интерфейсе. Удачи в разработке вашего проекта на ESP8266!