我正在 ESP32 上使用 ESPAsyncWebServer 做一个简单的示例。在这种情况下,我编写了一个 html 文件(有一个滑块和一个按钮)并在浏览器上对其进行了测试,直到内容看起来不错。然后我将它集成到 ESP32 的 C++ 源代码中。它可以正常工作并且看起来与预期一致,直到我不添加回调来读取滑块的值。 这是完整的源代码:
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
// Replace with your network credentials
const char ssid[] = "Vodafone-A40881218";
const char pswd[] = "rJbFMktHCcqN67Ye";
const int output = 2;
String sliderValue = "0";
// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
const char* PARAM_INPUT = "value";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
#if 0
const char old_index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP Web Server</title>
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 2.3rem;}
p {font-size: 1.9rem;}
body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
.slider { -webkit-appearance: none; margin: 14px; width: 360px; height: 25px; background: #FFD65C; outline: none; -webkit-transition: .2s; transition: opacity .2s;}
.slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 35px; height: 35px; background: #003249; cursor: pointer;}
.slider::-moz-range-thumb { width: 35px; height: 35px; background: #003249; cursor: pointer; }
button { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:20%;color:white;font-size:130%; }
.buttons { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:15%;color:white;font-size:80%; }
.buttonsm { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:9%; color:white;font-size:70%; }
.buttonm { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:15%;color:white;font-size:70%; }
.buttonw { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:40%;color:white;font-size:70%; }
.buttong { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:40%;color:white;font-size:130%; }
</style>
</head>
<body>
<h2>ESP Web Server</h2>
<p><span id="textSliderValue">%SLIDERVALUE%</span></p>
<p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="21" value="%SLIDERVALUE%" step="1" class="slider"></p>
<a href='/setup'><button class='button'>SETUP</button></a>
<script>
function updateSliderPWM(element) {
var sliderValue = document.getElementById("pwmSlider").value;
document.getElementById("textSliderValue").innerHTML = sliderValue;
console.log(sliderValue);
var xhr = new XMLHttpRequest();
xhr.open("GET", "/slider?value="+sliderValue, true);
xhr.send();
}
</script>
</body>
</html>
)rawliteral";
#endif
const char index_html[] = R"rawliteral(
<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP Web Server</title>
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 2.3rem;}
p {font-size: 1.9rem;}
body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
.slider { width: 360px; }
.slider::-webkit-slider-thumb { width: 50px; height: 50px; }
.slider::-moz-range-thumb { width: 50px; height: 50px; }
button { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:40%;color:white;font-size:130%; }
.buttons { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:15%;color:white;font-size:80%; }
.buttonx { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:9%; color:white;font-size:70%; }
.buttonm { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:15%;color:white;font-size:70%; }
.buttonw { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:40%;color:white;font-size:70%; }
.buttong { border-radius:0.5em;background:#C20000;padding:0.3em 0.3em;width:40%;color:white;font-size:130%; }
</style>
</head>
<body>
<h2>ESP Web Server</h2>
<p><span id="textSliderValue">%SLIDERVALUE%</span></p>
<p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="21" value="%SLIDERVALUE%" step="1" class="slider"></p>
<a href='/setup'><button class='button'>SETUP</button></a>
<script>
function updateSliderPWM(element) {
var sliderValue = document.getElementById("pwmSlider").value;
document.getElementById("textSliderValue").innerHTML = sliderValue;
console.log(sliderValue);
var xhr = new XMLHttpRequest();
xhr.open("GET", "/slider?value="+sliderValue, true);
xhr.send();
}
</script>
</body>
</html>
)rawliteral";
// Replaces placeholder with button section in your web page
String processor(const String& var)
{
//Serial.println(var);
if (var == "SLIDERVALUE"){
return sliderValue;
}
return String();
}
#include <Preferences.h>
Preferences Pref;
int32_t g_iVolume = 0;
void setup()
{
// Serial port for debugging purposes
Serial.begin(115200);
Pref.begin("datasetup", false);
g_iVolume = Pref.getInt("volume", 5);
Serial.print("volume="); Serial.println(g_iVolume);
sliderValue = String(g_iVolume);
Pref.end();
// Connect to Wi-Fi
WiFi.begin(ssid, pswd);
Serial.println("Connecting ...");
while (WiFi.status() != WL_CONNECTED)
{ // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
delay(250);
Serial.print('.');
}
// Print ESP Local IP Address
Serial.println(WiFi.localIP());
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Send a GET request to <ESP_IP>/slider?value=<inputMessage>
server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage;
// GET input1 value on <ESP_IP>/slider?value=<inputMessage>
if (request->hasParam(PARAM_INPUT)) {
inputMessage = request->getParam(PARAM_INPUT)->value();
sliderValue = inputMessage;
int ival = sliderValue.toInt();
Serial.print("ival="); Serial.println(ival);
Pref.begin("datasetup", false);
size_t st = Pref.putInt("volume", ival);
Pref.end();
Serial.print("st="); Serial.println(st);
Pref.begin("datasetup", false);
int vol = Pref.getInt("volume", -1);
Serial.print("volume="); Serial.println(vol);
Pref.end();
}
else {
inputMessage = "No message sent";
}
Serial.println(inputMessage);
request->send(200, "text/plain", "OK");
});
// Start server
server.begin();
}
//------------------------------------------------------------------------
void loop()
{
// put your main code here, to run repeatedly:
}
//------------------------------------------------------------------------
第一个图像使用 nullptr 而不是处理器,第二个图像使用处理器回调。
我发现问题了。 ESPAsyncWebServer 的作者决定使用 % 字符作为模板处理器占位符的分隔符。不幸的是,% 在 CSS 和 JavaScript 中非常常见,因此,在 HTML 文件或字符串中编写 CSS 和 JavaScript 无法按预期工作,因为 % 错误地解释为文本块的分隔符,这些文本块不是占位符,而是 CSS 或 JavaScript代码。目前没有解决方法,只是不要在 CSS 和 JavaScript 中使用 % 。
我遇到了同样的问题,我通过将分隔符 (%) 更改为 ($) 来修复它。 为此,您必须修改文件“ESPAsyncWebServer\src\WebResponseImpl.h”中的“TEMPLATE_PLACEHOLDER”的定义
#ifndef TEMPLATE_PLACEHOLDER
#define TEMPLATE_PLACEHOLDER '$' <<<<
#endif
我不知道您使用的是哪个版本的“ESPAsyncWebServer”,但我使用的是“ESPAsyncWebServer-esphome(版本:3.0.0)”库中的版本。
在此,如果没有创建变量“TEMPLATE_PLACEHOLDER”,则默认创建的值为“$”,您可以将其更改为您想要的值。 在您显示的代码中,它表示如果定义了该变量。它是未定义的,并使用新值再次定义,但如果它仍然不存在,则该代码段不执行任何操作。你应该把它改成这样:
#ifdef TEMPLATE_PLACEHOLDER //if the macro TEMPLATE_PLACEHOLDER is defined
#undef TEMPLATE_PLACEHOLDER //un-define it
#endif
#define TEMPLATE_PLACEHOLDER '$' // define it with the new value
很高兴发现 TEMPLATE_PLACEHOLDER '%' 是问题所在。 发现它带有诸如“width: 100%;”之类的文本
而不是编辑 WebResponseImpl.h
在 platformio.ini 的 build_flags 部分添加
-D TEMPLATE_PLACEHOLDER=36 ; '$'
请注意 TEMPLATE_PLACEHOLDER='$' 不起作用
确实如此。 我在我的主程序中检查了这样做:
#ifdef TEMPLATE_PLACEHOLDER //if the macro TEMPLATE_PLACEHOLDER is defined
#undef TEMPLATE_PLACEHOLDER //un-define it
#define TEMPLATE_PLACEHOLDER '$'//redefine it with the new value
#endif
但这不起作用... 也许某个大师知道如何以一种单独的 #define 推翻 WebResponseImpl.h 中的定义的方式来确定定义的优先级