Im using a Teensy 3.2 microcontroller paired with an ESP8266. Right now im just trying to serve a simple HTML web page that is updated with ajax. I can connect to the ESP and serve a page but im having trouble updating the page with XML data. The problem is somewhere in the loop function. Im not sure how to get the ESP to properly send XML data, or maybe im missing a critical function. Help greatly appreciated!
#define LED1 11
#define LED2 12
#define BUFFER_SIZE 4096
#define SSID "xxxx" // change this to match your WiFi SSID
#define PASS "xxxx" // change this to match your WiFi password
#define PORT "8080" // Port 8080 is default webserver port
char buffer[BUFFER_SIZE];
int n = 0;
String webSite, javaScript, XML, header, content;
void buildWebsite() {
header = "HTTP/1.1 200 OK\r\n";
header += "Content-Type: text/html\r\n";
header += "Connection: close\r\n";
//header += "Refresh: 5\r\n";
buildJavascript();
content = "<!DOCTYPE HTML>\n";
content += javaScript;
content += "<BODY onload='process()'>\n";
content += "<BR>This is the ESP website.<BR>\n";
content += "Runtime = <A id='runtime'></A>\n";
content += "</BODY>\n";
content += "</HTML>\n";
header += "Content-Length:";
header += (int)(content.length());
header += "\r\n\r\n";
webSite = header + content;
}
void buildJavascript() {
javaScript = "<SCRIPT>\n";
javaScript += "var xmlHttp = createXmlHttpObject();\n";
javaScript += "function createXmlHttpObject() {\n";
javaScript += " if(window.XMLHttpRequest) {\n";
javaScript += " xmlHttp = new XMLHttpRequest();\n";
javaScript += " } else {\n";
javaScript += " xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');\n";
javaScript += " }\n";
javaScript += " return xmlHttp;\n";
javaScript += "}\n";
javaScript += "function process(){\n";
javaScript += " if(xmlHttp.readyState == 0 || xmlHttp.readyState == 4){\n";
javaScript += " xmlHttp.open('GET','xml',true);\n";
javaScript += " xmlHttp.onreadystatechange = handleServerResponse();\n"; // no brackets?????
javaScript += " xmlHttp.send();\n";
javaScript += " }\n";
javaScript += " setTimeout('process()',1000);\n";
javaScript += "}\n";
javaScript += "function handleServerResponse(){\n";
javaScript += " if(xmlHttp.readyState == 4 && xmlHttp.status == 200){\n";
javaScript += " xmlResponse = xmlHttp.responseXML;\n";
javaScript += " xmldoc = xmlResponse.getElementsByTagName('response');\n";
javaScript += " message = xmldoc[0].firstChild.nodeValue;\n";
javaScript += " document.getElementById('runtime').innerHTML = message;\n";
javaScript += " }\n";
javaScript += "}\n";
javaScript += "</SCRIPT>\n";
}
void buildXML() {
XML = "<?xml version='1.0' encoding='UTF-8'?>\n";
XML += "<response>\n";
XML += millis2time();
XML += "</response>\n";
}
String millis2time() {
String Time = "";
unsigned long ss;
byte mm, hh;
ss = millis() / 1000;
hh = ss / 3600;
mm = (ss - hh * 3600) / 60;
ss = (ss - hh * 3600) - mm * 60;
if (hh < 10)Time += "0";
Time += (String)hh + ":";
if (mm < 10)Time += "0";
Time += (String)mm + ":";
if (ss < 10)Time += "0";
Time += (String)ss;
return Time;
}
/*******************************************************************
* PROGRAM SETUP
********************************************************************/
void setup() {
delay(1000);
Serial1.begin(115200); // Teensy to ESP8266
Serial.begin(115200); // Teensy to USB Serial
Serial.println("Begin program.");
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
// Initialize ESP8266.
setupWiFi();
}
/*******************************************************************
* DEVICE FUNCTIONS
********************************************************************/
// Read line responses from ESP8266.
bool read_till_eol() {
static int i = 0;
if (Serial1.available()) {
buffer[i++] = Serial1.read();
if (i == BUFFER_SIZE) i = 0;
if (i > 1 && buffer[i - 2] == 13 && buffer[i - 1] == 10) {
buffer[i] = 0;
i = 0;
Serial.print(buffer);
return true;
}
}
return false;
}
// Listen for ESP8266 response. By default we are looking for OK\r\n
char OK[] = "OK\r\n";
byte wait_for_esp_response(int timeout, char* term = OK) {
unsigned long t = millis();
bool found = false;
int i = 0;
int len = strlen(term); // compute length of (string)
// wait for at most timeout milliseconds, or if OK\r\n is found
while (millis() < t + timeout) {
if (Serial1.available()) {
digitalWrite(LED2, HIGH);
buffer[i++] = Serial1.read();
if (i >= len) {
if (strncmp(buffer + i - len, term, len) == 0) {
found = true;
break;
}
}
digitalWrite(LED2, LOW);
}
}
buffer[i] = 0;
Serial.print(buffer);
return found;
}
/*******************************************************************
* LOOP
********************************************************************/
void loop() {
int ch_id, packet_len;
char *pb;
// Look for received IDP (unsolicited data packet) from browser refresh.
if (read_till_eol()) {
if (strncmp(buffer, "+IPD,", 5) == 0) // If strings match...
{
// Request: (+IPD, connection channel, data length)
sscanf(buffer + 5, "%d,%d", &ch_id, &packet_len);
if (packet_len > 0) {
// Read serial until packet_len character received
// start from :
pb = buffer + 5;
while (*pb != ':') pb++;
pb++;
if (strncmp(pb, "GET / HTTP", 10) == 0)
{
// Send HTML data.
wait_for_esp_response(2000);
Serial.println("Serving HTML ->");
buildWebsite();
serve(webSite, ch_id);
}
else if (strncmp(pb, "GET /xml", 8) == 0)
{
// Send XML data.
wait_for_esp_response(2000);
Serial.println("Serving XML ->");
buildXML();
serve(XML, ch_id);
Serial.println(millis2time());
}
}
}
}
}
/*******************************************************************
* SEND DATA
********************************************************************/
// Send the data to the ESP8266.
void serve(String data, int ch_id)
{
Serial1.print("AT+CIPSEND=");
Serial1.print(ch_id);
Serial1.print(",");
Serial1.println(data.length());
if (wait_for_esp_response(1000)) {
Serial1.print(data);
}
else {
Serial1.print("AT+CIPCLOSE=");
Serial1.println(ch_id);
}
}
/*******************************************************************
* SETUP WIFI
********************************************************************/
void setupWiFi() {
// Turn on echo.
Serial1.println("ATE1");
wait_for_esp_response(1000);
// Set mode 3 (client + AP).
Serial1.println("AT+CWMODE=3");
wait_for_esp_response(1000);
// Reset WiFi module.
Serial1.print("AT+RST\r\n");
wait_for_esp_response(1500);
// Join AP.
Serial1.print("AT+CWJAP=\"");
Serial1.print(SSID);
Serial1.print("\",\"");
Serial1.print(PASS);
Serial1.println("\"");
wait_for_esp_response(5000);
// Start server.
Serial1.println("AT+CIPMUX=1");
wait_for_esp_response(1000);
// Create TCP Server.
Serial1.print("AT+CIPSERVER=1,");
Serial1.println(PORT);
wait_for_esp_response(1000);
// Set the automatic socket client disconnection timeout from 1 to 28800 seconds.
Serial1.println("AT+CIPSTO=6000");
wait_for_esp_response(1000);
Serial1.println("AT+GMR");
wait_for_esp_response(1000);
Serial1.println("AT+CWJAP?");
wait_for_esp_response(1000);
Serial1.println("AT+CIPSTA?");
wait_for_esp_response(1000);
Serial1.println("AT+CWMODE?");
wait_for_esp_response(1000);
Serial1.println("AT+CIFSR");
wait_for_esp_response(5000);
Serial1.println("AT+CWLAP");
wait_for_esp_response(5000);
Serial1.println("AT+CIPSTATUS");
wait_for_esp_response(5000);
Serial.println("------------------------------------");
}
One of the problems is here:
xmlHttp.onreadystatechange = handleServerResponse();
You are not binding your handler to the readystatechange
event. You are just setting what handleServerResponse()
returns to xmlHttp.onreadystatechange
.
It should be:
xmlHttp.onreadystatechange = handleServerResponse;
The second problem is that you aren't sending your XML as a proper HTTP response.
You should send it with HTTP headers like you are sending your HTML. And your XML response should set the Content-Type
header as text/xml
.
There are other possible problems/improvements like:
<script>
tag directly into the <html>
tag. It should be under the <head>
tag.Refresh: 5
header, but you are already refreshing your page with AJAX.millis2time()
returns and use document.getElementById('runtime').innerHTML = xmlHttp.responseText;
in your JavaScript.