[英]How to use ajax and setInterval on an ESP8266 HTML webpage served with Arduino
[英]How to prevent Ajax overflow/server crash? (Arduino/ESP8266 Environment)
我最近學習如何在Arduino中編程以在Adafruit HUZZAH ESP8266突破上主持HTML / CSS / Javascript網頁,所以如果我的方法完全關閉,請原諒我。
我正在使用Ajax更新頁面上的幾個壓力表值,它可以工作一段時間,但最終我得到了ERR_CONNECTION_TIMED_OUT
。
我總是得到這個,特別是當我剛啟動服務器的時候。 如果我重置wifi卡足夠的次數最終似乎加載很好,但它是有問題的,真的不穩定。
我也注意到ESP8266似乎一次只能處理一個用戶,一旦我嘗試從另一台計算機/手機上連接它就會崩潰服務器而我必須點擊重置按鈕才能讓它工作那個新主持人。
如果我只是以非常低效的方式使用Ajax或為什么會發生這種情況,有人可以幫助我理解嗎?
(刪除舊代碼以適應新代碼)
編輯:所以我相信我已經通過兩種方式改進了我的代碼:
我修改了數百個client.println()語句,而是將html / css / js內容存儲到四個單獨的char數組中,然后只在四個client.println()語句中打印出來。
我還通過在逗號分隔的字符串中一次性發送所有變量,然后我將過濾后的所有變量從五個(不計算對應於仍然需要的LED燈)的ajax調用數減少到一個相應的變量內容單獨出來。
但是,我仍然遇到頻繁但隨機的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();
}
}
我也注意到ESP8266似乎一次只能處理一個用戶
我建議嘗試不要使用可能導致問題的Keep-Alive
標頭。
client.println("Connection: keep-alive");
當您設置Keep-alive
保持連接始終打開,這可能會導致錯誤。
例如,如果您的服務器具有會話超時,則應始終保持會話處於活動狀態。
保持活動還有超時和最大請求
由於您每隔一段時間就會收到此錯誤,我認為這是服務器允許在保持連接上接受的超時+最大請求的問題。
沒有它,刪除並測試它。
嘗試使用數據包嗅探器Wireshark並截取結果
來自: https : //mcuoneclipse.com/2014/11/30/tutorial-web-server-with-the-esp8266-wifi-module/
發送repsonse后嘗試關閉連接:
關閉連接:CIPCLOSE
事情正在發揮作用:-)。 訣竅是我必須在發送數據后關閉連接。 我可以使用CIPCLOSE命令:
AT + CIPCLOSE =可用於關閉頻道。 所以我關閉了連接
AT + CIPCLOSE = 0
因此經過大量測試后,我得出的結論是ESP8266無法處理常量的ajax更新,最終使用websockets來完成我的任務(到目前為止,它似乎比ajax更穩定)。
以下是我的結果示例: https : //gist.github.com/bbx10/667e3d4f5f2c0831d00b
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.