ESP32 上的 Web 服务器:如何自动更新和显示来自服务器的传感器值?



我在 ESP32 上有一个 Web 服务器,在该服务器上有一个主页。我想每x秒自动更新一次主页上的传感器值(无需用户输入)。我无法访问文件系统。

传感器直接连接到 ESP32。传感器值在我的 C 程序中,存储在变量中并定期更新。变量是全局的,以便于使用。

我想到了Ajax(我没有经验),但是我能找到的所有示例和方法都使用文件来加载数据(在XMLHttpRequest().open(...网址....))。我没有文件,只有字符串,其中生成我的HTML和Javascript代码并将其发送到客户端。

我不知道如何更新我的价值观,并希望得到一些帮助。

我想尝试一些类似于 w3schools 的例子,但我不知道如何在那里获取值:

另一个页面的示例(我不使用此代码 - 我不能使用文件!

function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "ajax_info.txt", true);
xhttp.send();
}

以下是我在 ESP 上的 C 程序的一些代码:

HTML 字符串:

String html_document() {
String sHTML;
sHTML = "<!doctype html>";
sHTML +="<html>";
sHTML +="<html lang="de">";
/***************** head ****************/
sHTML +="<head>";
/****** avoid favicon requests **  ** <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon"> **/
sHTML +="<link rel="icon" href="data:;base64,iVBORw0KGgo="> ";
sHTML +="<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">";
//Anpassung an Viewport für unterschiedliche Devices
/***************** title ***************/
sHTML +="<title>LetsgoING IoT</title>";
sHTML +="<style>h1{display: flex; flex-flow: row wrap; justify-content: center;} </style>";
sHTML +="<style>h1{ color: green;}</style>";
sHTML +="<style>h2{display: flex; flex-flow: row wrap; justify-content: center;} </style>";
sHTML +="<style>h2{ color: blue;}</style>";
sHTML +="<style>h5{display: flex; flex-flow: row wrap; justify-content: center;} </style>";
sHTML +="<style>p{display: flex; flex-flow: row wrap; justify-content: center; margin-bottom: 3%;} </style>";
sHTML +="<style>p1{display: flex; flex-flow: row wrap; justify-content: center; margin-bottom: 0%;} </style>";
sHTML +="<style>p2{display: flex; flex-flow: row wrap; justify-content: center; margin-bottom: 0%;} </style>";
sHTML +="</head>";
/***************** body ****************/
sHTML+= "<body>";   //onload="window.setInterval(updateDiv, 15000);"
sHTML+= "<h1>LetsgoING</h1>";
sHTML+= "<h2>Internet der Dinge</h2>";
sHTML+= "<p1><a style="width:38%;"></a><a style="width:20%;color: green">LED ein</a> <a style="width:15%;" href="LEDON"><button> EIN </button></a> </a><a style="width:27%;"> </a></p1>";
sHTML+= "<p><a style="width:38%;"></a><a style="width:20%;color: red"  >LED aus</a> <a style="width:15%"; href="LEDOFF"><button>AUS</button></a><a style="width:27%;"> </a></p>";
sHTML+= "<h5>RGB-LED PWM-Werte</h5>";
sHTML+= "<form><p2>";
sHTML+= "<a style="width:38%;"></a> <a style="width:20%;color: red"> Rot</a>  <a style="width:15%;" ><input name="rot" type="number" min="0" max="255" step="1" value="80" ></a><a style="width:27%;"> </a>";
sHTML+= "<a style="width:38%;"></a> <a style="width:20%;color: green">Grün</a><a style="width:15%;" ><input name="gruen" type="number" min="0" max="255" step="1" value="80"></a><a style="width:27%;"> </a>";
sHTML+= "<a style="width:38%;"></a> <a style="width:20%;color: blue">Blau</a> <a style="width:15%;" ><input name="blau" type="number" min="0" max="255" step="1" value="80"></a><a style="width:27%;"> </a>";
sHTML+= "</p2>";
sHTML+= "<p><a style="width:38%;"></a> <a style="width:20%;">         </a>   <label style="width:15%;" ><input type="submit" value="senden"></label><a style="width:27%;"></a></p>";
sHTML+= "</form>";
sHTML+= "<h5>analoger Schwellwert</h5>";
sHTML+= "<form><p2><a style="width:38%;"></a> <a style="width:20%;"> <input name="schwell" type="number" min="0" max="1024" step="10" value="300"> </a> <a style="width:15%;"><input type="submit" value="senden"></a><a style="width:27%;"> </a></p2>";
//sHTML+= "<p><a style="width:28%;"></a> <a style="width:30%;">         </a>   <label style="width:15%;" ><input type="submit" value="senden"></label><a style="width:27%;"></a></p>";
sHTML+= "</form>";
sHTML+= "<h5>PWM-Wert</h5>";
sHTML+= "<form><p2><a style="width:38%;"></a> <a style="width:20%;"> <input name="pwm" type="number" min="0" max="255" step="1" value="0"> </a> <a style="width:15%;"><input type="submit" value="senden"></a><a style="width:27%;"> </a></p2>";
sHTML+= "</form>";
sHTML+= "<h5>Messwerte</h5>";
sHTML+="<p><a style="width:38%;"></a> <p3 id="an1"; style="width:20%;" href="anlg1">#-Wert-#</p3><a style="width:22%;">Analoger Pin 36   </a><a style="width:20%;"></a></p>";
sHTML+="<p><a style="width:38%;"></a> <p3 id="an2"; style="width:20%;">#-Wert-#</p3><a style="width:22%;">Analoger Pin 39   </a><a style="width:20%;"></a></p>";
sHTML+="<p><a style="width:38%;"></a> <p3 id="dig"; style="width:20%;">#-Wert-#</p3><a style="width:22%;">Digitaler Pin 5   </a><a style="width:20%;"></a></p>";
sHTML+= "</body>";
sHTML+= "</html>";
return sHTML;
}

圈:

void loop() {
if (millis() - startTime >= 2000) {
startTime = millis();
/* Check if a client has connected */
client = server.available();
if (!client){
return;
}
/*Wait for the client to send data */
Serial.println("neuer Client verbunden------------------------------");
/*Count requests: */
request_counter ++;
unsigned long clTimeout = millis()+250;
while(!client.available() && (millis()<clTimeout) ) {
delay(1);
}
/***  publish Homepage ***/
client.print(html_document());
/* Read the first line of the clients request string "sHTML" until carriage return r */
sHTMLRequest = client.readStringUntil('r');
#ifdef DEBUGMODE
Serial.println("Antwort: ");
Serial.println(sHTMLRequest);
#endif
client.flush();
/* stop client, if request is empty */
if(sHTMLRequest=="") {
Serial.println("Leere Anfrage! - client gestoppt");
client.stop();
return;
}
#ifdef DEBUGMODE
Serial.println("Antwort2: ");
Serial.println(sHTMLRequest);
Serial.println ("---------");
Serial.print("DEBUG: Remote IP - Address : ");
for (int i = 0; i < 3; i++) {
Serial.print( client.remoteIP()[i]);
Serial.print(".");
}
Serial.println(client.remoteIP()[3]);
Serial.print("Seitenaufrufe: ");
Serial.println(request_counter);
Serial.println ("---------");
#endif
/**** call event handler **********/
eventHandler();
#ifdef DEBUGMODE
Serial.println("Zugewiesene PWM-Werte");
Serial.print("rot: ");
Serial.println(rot);
Serial.print("gruen: ");
Serial.println(gruen);
Serial.print("blau: ");
Serial.println(blau);
#endif
/* write PWM values for colors to channels*/
ledcWrite(1, rot);
ledcWrite(2, gruen);
ledcWrite(3, blau);
#ifdef DEBUGMODE
Serial.println(analog1);
#endif
}
UpdateValues();
}
/**** reads pin values **/
void UpdateValues() {
analog1 = analogRead(pinAnalog1);
analog2 = analogRead(pinAnalog2);
DigiOut = digitalRead(LEDpin);
}

下面是更新值并创建 JSON 字符串的函数:

void UpdateValues() {
analog1 = analogRead(pinAnalog1);
analog2 = analogRead(pinAnalog2);
DigiOut = digitalRead(LEDpin);
String strJson;
strJson = "(200,"application/json","{"pin36": ";
strJson+=analog1;
strJson+=", "pin39":";
strJson+= analog2;
strJson+=", "pin5": ";
strJson+=DigiOut;
strJson+="}")";
server.print(strJson);
}

选项 1

最简单的方法是通过将其添加到<head>来要求页面每 5 秒刷新一次:

sHTML +="<meta http-equiv="refresh" content="5">";

然后更改sHTML字符串以连接全局变量的值。 每次页面刷新时,它都会(应该)重建 html 并返回最新值。

选项 2

可以使用 ajax 检索最新值,然后频繁更新网页中显示数据的一小部分。

这里发生的情况是,您将 ESP32 设置为提供第二个 URL,该 URL 仅返回最新值作为 json 对象。然后将这些值注入到页面中,覆盖旧的值。

首先在<head>中添加一个指向jQuery的链接:

sHTML +="<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>";

<body>中添加带有 id 的spans以保存要更新的值。像这样:

sHTML+= "<h5>Messwerte</h5>";
sHTML+="<p>Analoger Pin 36</p>&nbsp;<span id='pin36'></span>";
sHTML+="<p>Analoger Pin 39</p>&nbsp;<span id='pin39'></span>";
sHTML+="<p>Analoger Pin 5</p>&nbsp;<span id='pin5'></span>";

为以下 JavaScript 创建sHTML,该脚本每 5 秒发出一次 ajax 请求,并在浏览器中更新最新值:

<script>
$(function() {
// request data every 5 seconds
setInterval(requestData, 5000);
function requestData() {
// ajax request for latest sensor data
$.get("/sensors")
.done(function(data) {
console.log(data);  // debugging - remove when satisfied
if (data) { // if the returned data is not null, update the values
$("#pin36").text(data.pin36);
$("#pin39").text(data.pin39);
$("#pin5").text(data.pin5);
} else { // a problem occurred
$("#pin36").text("?");
$("#pin39").text("?");
$("#pin5").text("?");
}
}).fail(function() {
console.log("The was a problem retrieving the data.");
});
}
});
</script>

检测到字符串/sensorssHTMLRequest时,您希望返回以下 json 格式:

{"pin36": 5.2, "pin39": 0.322, "pin5": 1}

在这一点上,我对你的设置还不够了解,无法进一步建议,但这些链接应该希望有助于C代码:http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html 和 http://randomnerdtutorials.com/esp32-web-server-arduino-ide/

如果您使用 https://github.com/nhatuan84/esp32-webserver 中的ESP32WebServer.h(有关详细信息,请参阅 http://www.iotsharing.com/2017/05/how-to-turn-esp32-into-web-server.html 的后半部分),则可以使用以下内容:

server.on("/sensors", handleSensorData);

/* this callback will be invoked when user request "/sensors" */
void handleSensorData() {
/* server responds 200 with a json payload */
/* although preferably concatenate your real sensor data here */
server.send(200, "application/json", "{"pin36": 5.2, "pin39": 0.322, "pin5": 1}"); 
}

最新更新