I have been recently learning how to program in Arduino to host an HTML/CSS/Javascript webpage on an Adafruit HUZZAH ESP8266 breakout, so please forgive me if my methods here are completely off.
I'm using Ajax to update a few pressure gauge values on a page and it works for a little while but eventually I just get ERR_CONNECTION_TIMED_OUT
.
I get this all the time, especially when I'm just starting the server up. If I reset the wifi card enough times eventually it seems to load just fine but it's problematic and really unstable.
I've also noticed that it seems that the ESP8266 can only handle one user on it at a time, and once I try to connect from another computer/phone it crashes the server and I have to hit the reset button to get it working on that new host.
Can someone help me understand if I'm just using Ajax in a really inefficient way or why this is happening?
(Old Code removed to fit new code)
EDIT: So I believe I've improved my code in two ways:
I've modified the hundreds of client.println() statements and instead stored the html/css/js content into four separate char arrays that are then printed out in only four client.println() statements.
I've also reduced the number of ajax calls I had from five (not counting the two corresponding to the LED light that are still necessary) down to one by sending all of the variables at once within a comma delimited string that I then filter the corresponding variable content out of individually.
However, I am still experiencing frequent, yet random ERR_CONNECTION_TIMED_OUT errors, and I say random because I recently was able to successfully run the server with consecutive successful ajax calls for almost two hours before error messages began cropping up, and then immediately after restarting the server more error messages came up within only 30 seconds.
At this point I can't figure out if I am still using ajax inefficiently or if this is simply due to limitations of the 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();
}
}