1

我使用的是与 ESP8266 配对的 Teensy 3.2 微控制器。现在我只是想提供一个使用 ajax 更新的简单 HTML 网页。我可以连接到 ESP 并提供一个页面,但我无法使用 XML 数据更新页面。问题出在循环函数的某个地方。我不确定如何让 ESP 正确发送 XML 数据,或者我可能错过了一个关键功能。非常感谢帮助!

#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("------------------------------------");

}
4

1 回答 1

0

问题之一在这里:

xmlHttp.onreadystatechange = handleServerResponse();

您没有将处理程序绑定到readystatechange事件。您只是在设置handleServerResponse()返回的内容xmlHttp.onreadystatechange

它应该是:

xmlHttp.onreadystatechange = handleServerResponse;

第二个问题是您没有将 XML 作为正确的 HTTP 响应发送。
您应该像发送 HTML 一样使用 HTTP 标头发送它。并且您的 XML 响应应将Content-Type标头设置为text/xml.

还有其他可能的问题/改进,例如:

  1. 您将<script>标签直接放入<html>标签中。它应该在<head>标签下。
  2. 您正在使用Refresh: 5标题,但您已经在使用 AJAX 刷新页面。
  3. 如果您只想要一个值,则不需要发送 XML。您可以只发送millis2time()返回的内容并document.getElementById('runtime').innerHTML = xmlHttp.responseText;在 JavaScript 中使用。
  4. 您的 HTML 代码是静态的,在请求之间不会发生变化。在每个 HTTP 请求上构建整个请求是没有意义的。
    您可以将整个请求字符串放入一个 const 变量中,然后提供它。
于 2015-11-26T22:58:53.033 回答