2015-11-21 3 views
1

Im с использованием микроконтроллера Teensy 3.2 в паре с ESP8266. Прямо сейчас я просто пытаюсь обслуживать простую веб-страницу HTML, которая обновляется с помощью ajax. Я могу подключиться к ESP и обслуживать страницу, но им не удалось обновить страницу с помощью XML-данных. Проблема находится где-то в функции цикла. Я не уверен, как заставить ESP правильно отправлять XML-данные или, может быть, не хватать критической функции. Помощь очень ценится!ESP8266 + Teensyduino Web Server

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

} 
+0

Как именно это не работает? –

+0

Похоже, что XMLHTTPRequest отправляется после загрузки страницы, но веб-страница никогда не обновляется данными XML, отправленными с сервера. Мне нужно обновить страницу каждую секунду новой строкой времени. Я опубликую серийный выпуск ниже. –

+0

Поэтому я думаю, что мне просто нужен ESP, чтобы отправлять XML-данные по адресу: ip/port/xml. Я не уверен, как отформатировать эти данные для отправки с ESP. –

ответ

0

Одна из проблем здесь:

xmlHttp.onreadystatechange = handleServerResponse(); 

Вы не являются обязательными для обработчика к событию readystatechange. Вы просто устанавливаете то, что handleServerResponse() возвращается к xmlHttp.onreadystatechange.

Оно должно быть:

xmlHttp.onreadystatechange = handleServerResponse; 

Вторая проблема заключается в том, что вы не отправки XML в качестве надлежащего ответа HTTP.
Вы должны отправить его с HTTP-заголовками, как будто вы отправляете свой HTML-код. И ваш ответ 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-запроса.
    Вы можете просто поместить всю строку запроса в константную переменную, а затем подать ее.
+0

Спасибо за помощь. Я добавил соответствующие заголовки, и страница теперь обновляется с данными XML. Можете ли вы представить пример построения статической строки запроса? Я понимаю, что вы имеете в виду, но немного запутался в том, как писать. –

+0

@SeanRagsdale вы можете просто запустить 'buildWebsite()' один раз в 'setup()', так как 'webSite' будет одинаковым каждый раз. Затем вы можете использовать 'webSite', не вызывая сначала' buildWebsite() '. Или вы можете определить 'webSite' как полную строку в вашем коде. В этом случае вам не понадобится 'buildWebsite()'. –

+0

Делает смысл. Сейчас все отлично работает. Благодаря! –