【发布时间】:2016-04-22 21:45:37
【问题描述】:
我最近一直在学习如何在 Arduino 中编程,以便在 Adafruit HUZZAH ESP8266 突破上托管 HTML/CSS/Javascript 网页,所以如果我在这里的方法完全关闭,请原谅我。
我正在使用 Ajax 更新页面上的一些压力表值,它工作了一段时间,但最终我得到了ERR_CONNECTION_TIMED_OUT。
我总是这样,尤其是当我刚刚启动服务器时。如果我最终将 wifi 卡重置足够多次,它似乎加载得很好,但是 这是有问题的,而且非常不稳定。
我还注意到,似乎 ESP8266 一次只能处理一个用户,一旦我尝试从另一台计算机/电话连接它会使服务器崩溃,我必须点击重置按钮才能获得它在那个新主机上工作。
有人可以帮助我了解我是否只是以一种非常低效的方式使用 Ajax 或者为什么会发生这种情况?
(删除旧代码以适应新代码)
编辑: 所以我相信我已经通过两种方式改进了我的代码:
我已经修改了数百个 client.println() 语句,而是将 html/css/js 内容存储到四个单独的 char 数组中,然后仅在四个 client.println() 语句中打印出来。
我还通过在逗号分隔的范围内一次发送所有变量,将我的 ajax 调用数量从五个(不包括与仍然需要的 LED 灯对应的两个)减少到一个然后我单独过滤出相应的变量内容的字符串。
但是,我仍然经常遇到随机的 ERR_CONNECTION_TIMED_OUT 错误,我说是随机的,因为我最近能够通过连续成功的 ajax 调用成功运行服务器近两个小时,然后开始出现错误消息,然后立即出现重新启动服务器仅 30 秒内就出现了更多错误消息。
此时我不知道我是否仍然在低效使用 ajax,或者这仅仅是由于 ESP8266 的限制?
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <Wire.h>
WiFiServer server(80);
WiFiClient client;
String HTTP_req;
String req;
double test = 42;
String LEDstatus = "off";
(Some variable initializations removed for space)
char webpagePartOne[2500];
char webpagePartTwo[2500];
char webpagePartThree[2500];
char webpagePartFour[2500];
void switchLEDon() {
//Serial.println("TEST LED ON");
int ledStatusLength = 1;
subsys = 0x13;
//Account for the end of message
messageLength = ledStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
//Serial.println("");
//Serial.println("TURN LED ON|");
LEDstatus = "on";
} //end switchLEDon
void switchLEDoff() {
(almost the same as switchLEDon(), removed to lower char count here)
} //end switchLEDoff
void setStatus(WiFiClient cl) {
currFluid += 22;
if(currFluid > 100)
{
currFluid -= 100;
}
cl.print(currNumRefresh);
cl.print(",");
cl.print(currPressureC);
cl.print(",");
cl.print(currPressureD);
cl.print(",");
cl.print(currPressureE);
cl.print(",");
cl.print(currFluid);
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
WiFi.begin(SSID, pass);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Start the server
server.begin();
Serial.println("Server started");
Serial.println(WiFi.localIP());
}
void loop() {
//Communication Protocol
if(Serial.available() > 0)
{
//Serial.print("SERIAL.AVAILABLE: ");
//Serial.println(Serial.available());
//delay(1000);
if(initialCounter == 0)
{
rx_byte = Serial.read();
/*
//Print Start of Message
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rx_byte, HEX);
*/
//Serial.println(rx_byte, BIN);
//Serial.println(rx_byte);
initialCounter++;
}
if((!messageBegun) && (rx_byte == som))
{
messageBegun = true;
//Serial.println("MESSAGE BEGUN TRUE");
} //end if (messageInProgress && rx_byte)
if((messageBegun) && (!messageInProgress))
{
serialCurrent = Serial.available();
if(serialCurrent > 0)
{
receivedMessageLength = (uint8_t)Serial.read();
/*
Serial.print("MESSAGE LENGTH: ");
Serial.println(receivedMessageLength);
*/
messageBegun = false;
messageInProgress = true;
//Serial.println("MESSAGE IN PROGRESS TRUE");
} //end if (serialCurrent)
} //end if (messageBegun && messageInProgress)
if(messageInProgress)
{
serialCurrent = Serial.available();
if(serialCurrent >= receivedMessageLength)
{
Serial.readBytes(rxBuff, receivedMessageLength);
if((byte)rxBuff[receivedMessageLength-1] != eom)
{
//Serial.println("ERROR");
//Serial.write(Serial.read());
} //end if (rxBuff != eom)
else
{
messageInProgress = false;
for(int i=0; i<receivedMessageLength; i++)
{
if(rxBuff[i] == eom)
{
/*
//Print End of Message
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rxBuff[i], HEX);
*/
initialCounter = 0;
receivedMessageLength = 0;
} //end if
else if(i == 0)
{
receivedSubsys = rxBuff[i];
/*
//Print Subsystem
Serial.print("0x");
if(rx_byte<0x10)
{
Serial.print("0");
}
Serial.println(rxBuff[i], HEX);
*/
} //end if
else
{
if(receivedSubsys == 0x14)
{
currNumRefresh = rxBuff[i];
} //end if
else if(receivedSubsys == 0x15)
{
currPressureC = rxBuff[i];
} //end else if
else if(receivedSubsys == 0x16)
{
currPressureD = rxBuff[i];
} //end else if
else if(receivedSubsys == 0x17)
{
currPressureE = rxBuff[i];
} //end else if
} //end else
} //end for
} //end else
} //end if (serialCurrent)
} //end if (messageInProgress)
} //end if (Serial.available)
WiFiClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
String currentLine = "";
/*
if(digitalRead(LED_PIN))
{
LEDstatus = "on";
}
else if(!digitalRead(LED_PIN))
{
LEDstatus = "off";
}
*/
while (client.connected()) {
if (client.available()) {
char c = client.read();
HTTP_req += c;
if (c == '\n' && currentLineIsBlank)
{
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: keep-alive");
client.println();
//LED Functions
if (HTTP_req.indexOf("ajax_LED_switch_on") > -1) {
switchLEDon();
}
else if(HTTP_req.indexOf("ajax_LED_switch_off") > -1) {
switchLEDoff();
}
else if(HTTP_req.indexOf("ajax_set_status") > -1) {
setStatus(client);
}
else {
//Part One
strcpy(webpagePartOne,"<!DOCTYPE html>\n");
strcat(webpagePartOne,"<html>\n");
strcat(webpagePartOne,"<head>\n");
strcat(webpagePartOne,"<title>Adafruit HUZZAH ESP8266</title>\n");
strcat(webpagePartOne,"<style type='text/css'>\n");
(css here removed for space)
//Part Two
(Some more css here removed for space)
strcat(webpagePartTwo,"</style>\n");
strcat(webpagePartTwo,"<script>\n");
strcat(webpagePartTwo,"var currPressureTest = 0;\n");
strcat(webpagePartTwo,"var currFluidTest = 0;\n");
//Set Status function
strcat(webpagePartTwo,"function setStatus(){\n");
strcat(webpagePartTwo,"nocache = \"&nocache=\"+ Math.random() * 1000000;\n");
strcat(webpagePartTwo,"var request = new XMLHttpRequest();\n");
strcat(webpagePartTwo,"request.onreadystatechange = function() {\n");
strcat(webpagePartTwo,"if (this.readyState == 4) {\n");
strcat(webpagePartTwo,"if (this.status == 200) {\n");
strcat(webpagePartTwo,"if (this.responseText != null) {\n");
strcat(webpagePartTwo,"var totalStatus = this.responseText;\n");
strcat(webpagePartTwo,"var splitStatus = totalStatus.split(',');\n");
//strcat(webpagePartThree,"alert('Pressure C: ' + splitStatus[0] + ', Pressure D: ' + splitStatus[1] + ', Pressure E: ' + splitStatus[2]);\n");
//Num Refresh
strcat(webpagePartTwo,"document.getElementById(\"demo\").innerHTML = splitStatus[0];\n");
//PRESSURE C
strcat(webpagePartTwo,"var pressureValue = document.querySelector('.gauge-c');\n");
strcat(webpagePartTwo,"pressureValue.style.transform = 'rotate('+ splitStatus[1] +'deg)';\n");
strcat(webpagePartTwo,"var pressureText = (((splitStatus[1])/180)*100).toFixed(0);\n");
strcat(webpagePartTwo,"document.getElementById(\"pressurePercentC\").innerHTML = pressureText + '%';\n");
strcat(webpagePartTwo,"if(pressureText > 75){\n");
strcat(webpagePartTwo,"pressureValue.style.background = 'red';\n");
strcat(webpagePartTwo,"}\n");
strcat(webpagePartTwo,"else if(pressureText > 25 && pressureText < 75){\n");
strcat(webpagePartTwo,"pressureValue.style.background = 'yellow';\n");
strcat(webpagePartTwo,"}\n");
strcat(webpagePartTwo,"else if(pressureText < 25){\n");
strcat(webpagePartTwo,"pressureValue.style.background = 'green';\n");
strcat(webpagePartTwo,"}\n");
//PRESSURE D
strcat(webpagePartTwo,"var pressureValue = document.querySelector('.gauge-d');\n");
strcat(webpagePartTwo,"pressureValue.style.transform = 'rotate('+ splitStatus[2] +'deg)';\n");
strcat(webpagePartTwo,"var pressureText = (((splitStatus[2])/180)*100).toFixed(0);\n");
strcat(webpagePartTwo,"document.getElementById(\"pressurePercentD\").innerHTML = pressureText + '%';\n");
strcat(webpagePartTwo,"if(pressureText > 75){\n");
strcat(webpagePartTwo,"pressureValue.style.background = 'red';\n");
strcat(webpagePartTwo,"}\n");
strcat(webpagePartTwo,"else if(pressureText > 25 && pressureText < 75){\n");
strcat(webpagePartTwo,"pressureValue.style.background = 'yellow';\n");
strcat(webpagePartTwo,"}\n");
strcat(webpagePartTwo,"else if(pressureText < 25){\n");
strcat(webpagePartTwo,"pressureValue.style.background = 'green';\n");
strcat(webpagePartTwo,"}\n");
//PRESSURE E
strcat(webpagePartTwo,"var pressureValue = document.querySelector('.gauge-e');\n");
strcat(webpagePartTwo,"pressureValue.style.transform = 'rotate('+ splitStatus[3] +'deg)';\n");
strcat(webpagePartTwo,"var pressureText = (((splitStatus[3])/180)*100).toFixed(0);\n");
strcat(webpagePartTwo,"document.getElementById(\"pressurePercentE\").innerHTML = pressureText + '%';\n");
//Part Three
strcpy(webpagePartThree,"if(pressureText > 75){\n");
strcat(webpagePartThree,"pressureValue.style.background = 'red';\n");
strcat(webpagePartThree,"}\n");
strcat(webpagePartThree,"else if(pressureText > 25 && pressureText < 75){\n");
strcat(webpagePartThree,"pressureValue.style.background = 'yellow';\n");
strcat(webpagePartThree,"}\n");
strcat(webpagePartThree,"else if(pressureText < 25){\n");
strcat(webpagePartThree,"pressureValue.style.background = 'green';\n");
strcat(webpagePartThree,"}\n");
//FLUID LEVEL
strcat(webpagePartThree,"var fluidValue = document.querySelector('.fluidMeter');\n");
strcat(webpagePartThree,"fluidValue.value = splitStatus[4];\n");
strcat(webpagePartThree,"var fluidText = splitStatus[4];\n");
strcat(webpagePartThree,"document.getElementById(\"fluidPercent\").innerHTML = fluidText + '%';\n");
strcat(webpagePartThree,"}}}}\n");
strcat(webpagePartThree,"request.open(\"GET\", \"ajax_set_status\" + nocache, true);\n");
strcat(webpagePartThree,"request.send(null);\n");
strcat(webpagePartThree,"setTimeout('setStatus()', 5000);\n");
strcat(webpagePartThree,"}\n");
strcat(webpagePartThree,"function LEDswitch(){\n");
strcat(webpagePartThree,"var LEDswitchCheck = document.getElementById('myonoffswitch').checked;\n");
strcat(webpagePartThree,"if(LEDswitchCheck){\n");
strcat(webpagePartThree,"nocache = \"&nocache=\"+ Math.random() * 1000000;\n");
strcat(webpagePartThree,"var request = new XMLHttpRequest();\n");
strcat(webpagePartThree,"request.onreadystatechange = function() {\n");
strcat(webpagePartThree,"if (this.readyState == 4) {\n");
strcat(webpagePartThree,"if (this.status == 200) {\n");
strcat(webpagePartThree,"if (this.responseText != null) {\n");
//strcat(webpagePartThree,"document.getElementById(\"LEDbtn\").innerHTML = this.responseText;\n");
strcat(webpagePartThree,"}}}}\n");
strcat(webpagePartThree,"request.open(\"GET\", \"ajax_LED_switch_on\" + nocache, true);\n");
strcat(webpagePartThree,"request.send(null);\n");
strcat(webpagePartThree,"}\n");
strcat(webpagePartThree,"else if(!LEDswitchCheck) {\n");
strcat(webpagePartThree,"nocache = \"&nocache=\"+ Math.random() * 1000000;\n");
strcat(webpagePartThree,"var request = new XMLHttpRequest();\n");
strcat(webpagePartThree,"request.onreadystatechange = function() {\n");
strcat(webpagePartThree,"if (this.readyState == 4) {\n");
strcat(webpagePartThree,"if (this.status == 200) {\n");
strcat(webpagePartThree,"if (this.responseText != null) {\n");
//strcat(webpagePartThree,"document.getElementById(\"LEDbtn\").innerHTML = this.responseText;\n");
strcat(webpagePartThree,"}}}}\n");
strcat(webpagePartThree,"request.open(\"GET\", \"ajax_LED_switch_off\" + nocache, true);\n");
strcat(webpagePartThree,"request.send(null);\n");
strcat(webpagePartThree,"}\n");
strcat(webpagePartThree,"}\n");
strcat(webpagePartThree,"</script>\n");
strcat(webpagePartThree,"</head>\n");
strcat(webpagePartThree,"<body style='background-color:#558C89;' onload=\"setStatus();\">\n");
strcat(webpagePartThree,"<div style='background-color:#74AFAD;'>\n");
strcat(webpagePartThree,"<h1 style='text-decoration: underline;'>Adafruit HUZZAH ESP8266</h1>\n");
strcat(webpagePartThree,"</div>\n");
strcat(webpagePartThree,"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">\n</div>\n<div style=\"clear:both;\"></div><p>\n"); strcat(webpagePartThree,"<div style='background-color:#74AFAD;'>\n");
strcat(webpagePartThree,"<h2 style='color: red;'>LED Controls</h2>\n");
strcat(webpagePartThree,"<div id='LEDbtn' class='onoffswitch'>\n");
/*
if (LEDstatus == "on")
{
strcat(webpagePartThree,"<input type='checkbox' name='onoffswitch' class='onoffswitch-checkbox' id='myonoffswitch' checked='checked' onclick='LEDswitch()'>\n");
} //end if
*/
/*
else if(LEDstatus == "off")
{*/
strcat(webpagePartThree,"<input type='checkbox' name='onoffswitch' class='onoffswitch-checkbox' id='myonoffswitch' onclick='LEDswitch()'>\n");
//} //end else
strcat(webpagePartThree,"<label class='onoffswitch-label' for='myonoffswitch'>\n");
strcat(webpagePartThree,"<span class='onoffswitch-inner'></span>\n");
strcat(webpagePartThree,"<span class='onoffswitch-switch'></span>\n");
strcat(webpagePartThree,"</label>\n");
strcat(webpagePartThree,"</div>\n");
strcat(webpagePartThree,"</div>\n");
//Part Four
strcpy(webpagePartFour,"<div style='background-color:#74AFAD;'>\n");
strcat(webpagePartFour,"<h2 style='color: green;'>Num Refresh Test</h2>\n");
strcat(webpagePartFour,"<div id=\"demo\"><h2>Let AJAX change this text</h2></div>\n");
strcat(webpagePartFour,"</div>\n");
strcat(webpagePartFour,"</div>\n");
//strcat(webpagePartFour,"<div id='gaugeCounter'></div>\n");
strcat(webpagePartFour,"<div class='pressureRow'>\n");
strcat(webpagePartFour,"<div class='pressureContainer'>\n");
strcat(webpagePartFour,"<div class='gauge-a'></div>\n");
strcat(webpagePartFour,"<div class='gauge-b'></div>\n");
strcat(webpagePartFour,"<div class='gauge-c'></div>\n");
strcat(webpagePartFour,"<div class='gauge-data'><h1 id='pressurePercentC'>0%</h1></div>\n");
strcat(webpagePartFour,"</div>\n");
strcat(webpagePartFour,"<div class='pressureContainer'>\n");
strcat(webpagePartFour,"<div class='gauge-a'></div>\n");
strcat(webpagePartFour,"<div class='gauge-b'></div>\n");
strcat(webpagePartFour,"<div class='gauge-d'></div>\n");
strcat(webpagePartFour,"<div class='gauge-data'><h1 id='pressurePercentD'>0%</h1></div>\n");
strcat(webpagePartFour,"</div>\n");
strcat(webpagePartFour,"<div class='pressureContainer'>\n");
strcat(webpagePartFour,"<div class='gauge-a'></div>\n");
strcat(webpagePartFour,"<div class='gauge-b'></div>\n");
strcat(webpagePartFour,"<div class='gauge-e'></div>\n");
strcat(webpagePartFour,"<div class='gauge-data'><h1 id='pressurePercentE'>0%</h1></div>\n");
strcat(webpagePartFour,"</div>\n");
strcat(webpagePartFour,"</div>\n");
strcat(webpagePartFour,"<div class='fluidContainer'>\n");
strcat(webpagePartFour,"<meter class='fluidMeter' max='100' value='50' low='25' high='75' optimum='100'></meter>\n");
strcat(webpagePartFour,"<div class='fluid-data'><h1 id='fluidPercent'>0%</h1></div>\n");
strcat(webpagePartFour,"</div>\n");
strcat(webpagePartFour,"</body>\n");
strcat(webpagePartFour,"</html>");
client.print(webpagePartOne);
client.print(webpagePartTwo);
client.print(webpagePartThree);
client.print(webpagePartFour);
}
req = HTTP_req;
// Serial.print(HTTP_req);
HTTP_req = "";
break;
} //end if
}
}
delay(100);
client.stop();
}
}
【问题讨论】:
-
你能在串口输出上启用调试吗?您可以使用
Serial.setDebugOutput(true);启用基本调试,然后通过 Arduino ESP 构建选项启用更详细的日志记录 - Core + WiFi 可能会这样做。我有客户连续数周每秒从我的基于 ESP 的设备中抓取大型动态 JSON blob,没有任何问题,我记得看到这些 exact 相同的问题正在为它开发。通常,这是因为达到了最大客户端限制,或者未能及时为缓冲区提供服务,或者同样愚蠢的事情。如果是这种情况,您应该看到LmacRxBlk:1。或类似的东西 -
谢谢,但我最终找到了另一个解决方案。
标签: javascript css ajax arduino esp8266