好吧所以我过去两天一直在研究这个问题,但我仍然觉得自己无处可去。
我最近开始在 HUZZAH ESP8266 上使用 SPIFFS文件系统进行 Arduino 开发,例如 FSBrowser.ino 例如,虽然在分离代码方面做得很好,但随着我的代码不断增长,它在稳定性方面并不是很好。
自从我开始添加越来越多的javascript以来,我开始为各种文件弹出错误,无论是我的HTML / CSS / JS,我看到的主要错误是 ERR_CONTENT_LENGTH_MISMATCH 。 / p>
//File Read for File System
bool handleFileRead(String path)
{
if(mySerial)
mySerial.println("handleFileRead: " + path);
if(path.endsWith("/")) path += "index.htm";
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path))
{
if(SPIFFS.exists(pathWithGz))
path += ".gz";
File file = SPIFFS.open(path, "r");
if(mySerial)
mySerial.println("TEST: " + path + " FILE OPEN: " + file.size());
size_t sent = server.streamFile(file, contentType);
if(mySerial)
mySerial.println("TEST: " + path + " SIZE: " + file.size());
file.close();
if(mySerial)
mySerial.println("TEST: " + path + " FILE CLOSE");
return true;
} //end if
return false;
} //end function handleFileRead
所以在那之后我开始检查我从FSBrowser.h示例中复制的handleFileRead()函数,并且在测试了各种print语句后,似乎挂起发生在这一行中:
size_t sent = server.streamFile(file,contentType);
template<typename T> size_t streamFile(T &file, const String& contentType){
setContentLength(file.size());
if (String(file.name()).endsWith(".gz") &&
contentType != "application/x-gzip" &&
contentType != "application/octet-stream"){
sendHeader("Content-Encoding", "gzip");
}
send(200, contentType, "");
return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE);
}
所以从那里开始,我进入了 ESP8266WebServer.h ,找到了 streamFile()函数。进入这个函数后,我发现了这一行:
返回_currentClient.write(file,HTTP_DOWNLOAD_UNIT_SIZE);
由此我推断出两件事:
所以我跟踪了这个函数: size_t WiFiClient :: write(const uint8_t * buf,size_t size)。
size_t WiFiClient::write(const uint8_t *buf, size_t size)
{
SoftwareSerial mySerial(12,13);
mySerial.begin(115200);
if(mySerial)
{
mySerial.print("Size: ");
mySerial.println(size);
}
if (!_client || !size)
{
if(mySerial)
mySerial.println("FAILURE");
return 0;
}
if(mySerial)
mySerial.println("SUCCESS");
return _client->write(reinterpret_cast<const char*>(buf), size);
}
现在这不完全匹配,因为调用的write()函数的第一个参数是文件类型,而此函数的第一个参数是uint8_t,但是我放了一些打印尽管如此,这里的语句会在文件加载时执行,所以我相信我找到了正确的函数。
然而,现在我不知道如何从这里继续修复问题,因为只有一个递归调用并且错误似乎发生,因为罪魁祸首文件没有完成加载(至少根据chrome调试器的网络选项卡)
如您所见,style.css文件被列为 3千字节,这当然是错误的:我的css文件 27千字节。
所以看起来加载文件存在问题(这不是css文件独有的,它也发生在我的javascript文件中,似乎是随机的)。我已经尝试缩小所有文件,但它没有解决问题;所以我真的可以帮助确定如何解决这个问题。
现在我收到了其他来源的一些建议,尝试使用此库,这是 FSBrowser 代码的修改版本:https://github.com/me-no-dev/ESPAsyncWebServer
起初这似乎解决了我所有的问题。代码运行稳定,没有出现任何先前的问题。但是,自从切换到该库以来,我遇到了无数新问题:
最奇怪的事情发生了,似乎有些代码丢失了?
如果查看该照片中红色突出显示的行,您可以看到在removeClass()语句的中间,它会停止拼写出类(“deactiveSect”)并进一步启动一个完全不同的if语句在代码中。
然而,目前服务器上的代码部分相同:
你可以看到它似乎合并了第66和70行。
因此,虽然我使用的FSBrowser代码版本无法处理我正在使用的代码级别,但如果无数问题不断发生,我无法看到如何使用此修改后的库
这是我的其余代码(使用原始FSBrowser库)的源代码:
主要ino文件
//Header File
#include "HHIO_Portal.h"
//Function used to verify incoming information from the teensy to the wifi card via the communication protocol
void recInfoWifi()
{
/*
===============================
COMMUNICATION PROTOCOL - Removed due to post size limit
===============================
*/
} //end comProtocolWifi
//Function used to send information to the teensy in order to control the HHIO PTT
void sendInfoWifi()
{
unsigned long currTime = millis();
//SEND
if(currTime - prevTimeTest > testInterval)
{
prevTimeTest = currTime;
//Test Message
messageLength = 3;
subsys = SUBSYS_DBG;
messageContent = wifiCounter;
//Teensy Console
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
wifiCounter++;
} //end if (RECEIVE INFO)
} //end function sendInfoWifi
void setup()
{
//Initiate Serial connection to Teensy
Serial.begin(115200);
//This is for debugging/housekeeping (And all console messages that use mySerial as opposed to Serial)
mySerial.begin(115200);
/*
===============================
FILE SYSTEM
===============================
*/
SPIFFS.begin();
{
Dir dir = SPIFFS.openDir("/");
while (dir.next()) {
String fileName = dir.fileName();
size_t fileSize = dir.fileSize();
if(mySerial)
mySerial.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
} //end while
if(mySerial)
mySerial.printf("\n");
} //end SPIFFS BEGIN
/*
===============================
WIFI INIT
===============================
*/
if(mySerial)
mySerial.printf("Connecting to %s\n", ssid);
//Make the initial Wifi connection
if (String(WiFi.SSID()) != String(ssid)) {
WiFi.begin(ssid, password);
} //end if
//Wait for the Wifi to finish connecting
while (WiFi.status() != WL_CONNECTED) {
delay(500);
if(mySerial)
mySerial.print(".");
} //end while
//IP Address for webpage
if(mySerial)
{
mySerial.println("");
mySerial.print("Connected! IP address: ");
mySerial.println(WiFi.localIP());
} //end if
//Might not need this
MDNS.begin(host);
//Hostname for webpage
if(mySerial)
{
mySerial.print("Open http://");
mySerial.print(host);
mySerial.println(".local/edit to see the file browser");
} //end if
/*
===============================
SERVER INIT
===============================
*/
//list directory
server.on("/list", HTTP_GET, handleFileList);
//load editor
server.on("/edit", HTTP_GET, [](){
if(!handleFileRead("/edit.htm"))
server.send(404, "text/plain", "FileNotFound");
});
//create file
server.on("/edit", HTTP_PUT, handleFileCreate);
//delete file
server.on("/edit", HTTP_DELETE, handleFileDelete);
//first callback is called after the request has ended with all parsed arguments
//second callback handles file uploads at that location
server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload);
//called when the url is not defined here
//use it to load content from SPIFFS
server.onNotFound([](){
if(!handleFileRead(server.uri()))
server.send(404, "text/plain", "FileNotFound");
});
//get heap status, analog input value and all GPIO statuses in one json call
server.on("/all", HTTP_GET, [](){
String json = "{";
json += "\"heap\":"+String(ESP.getFreeHeap());
json += ", \"analog\":"+String(analogRead(A0));
json += ", \"gpio\":"+String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16)));
json += "}";
server.send(200, "text/json", json);
json = String();
});
//Start the server
server.begin();
if(mySerial)
mySerial.println("HTTP server started");
//Open the websocket connection in order to update the status values on the page without refreshing
webSocket.begin();
webSocket.onEvent(webSocketEvent);
} //end Setup
void loop()
{
//SEND INFO TO TEENSY
sendInfoWifi();
//RECEIVE INFO FROM TEENSY
recInfoWifi();
//CONTINUE WEBSOCKET CONNECTION
webSocket.loop();
//SERVE WEBPAGE TO THE USER
server.handleClient();
} //end loop
主要ino头文件
//Initiate necessary libraries
#include <SoftwareSerial.h>
#include <HHIO_Subsystems.h>
#include <ESP8266WiFi.h>
//#include <pfodESP8266WiFi.h>
#include <WebSocketsServer.h>
//#include <pfodESP8266WebServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <FS.h>
//Serial connection for debugging (RX, TX)
SoftwareSerial mySerial(12,13);
//SSID/Pass/Host
const char* ssid = "*****";
const char* password = "*****";
const char* host = "esp8266fs";
//Setup File System Connection
MDNSResponder mdns;
//Web Server
ESP8266WebServer server(80);
//File System
File fsUploadFile;
//Websocket
WebSocketsServer webSocket = WebSocketsServer(81);
//Invalid Message
uint8_t invalidMessageFlag = 0;
//Counter for testing serial connection
uint8_t wifiCounter = 0;
//Com. Protocol Buffer
uint8_t rxBuff[256];
//Start of Message
uint8_t som = 0x11;
//End of Message
uint8_t eom = 0x12;
//Subsystem variables
uint8_t subsys;
uint8_t receivedSubsys;
//Read Byte for Com. Protocol
uint8_t rx_byte = 0x00;
//Message length variables
uint8_t messageLength = 0;
uint8_t receivedMessageLength = 0;
//Message content variable
uint8_t messageContent;
//Variable to check incoming serial content
uint8_t serialCurrent;
//Counter used for verifying the som variable
int initialCounter = 0;
//Message progression variables
boolean messageBegun = false;
boolean messageInProgress = false;
//Variables currently used to read status info coming from the teensy (CURRENTLY RANDOMIZED INFO)
int currNumRefresh = 0;
int currMicroC = 0;
int currMicroD = 0;
int currMicroE = 0;
int currPressureC = 0;
int currPressureD = 0;
int currPressureE = 0;
int currValveStatusNumC = 0;
int currValveStatusNumD = 0;
int currValveStatusNumE = 0;
int currFluid = 0;
//Buffer for sending information from Arduino to the webpage
char statusbuf[256];
//Valve 1
String valveStatusC = "Closed";
String valveTubePropsC = "175px solid #00ADEF";
String valveColorC = "red";
//Valve 2
String valveStatusD = "Closed";
String valveTubePropsD = "175px solid #00ADEF";
String valveColorD = "red";
//Valve 3
String valveStatusE = "Closed";
String valveTubePropsE = "175px solid #00ADEF";
String valveColorE = "red";
//Variables for sending test message to teensy
long prevTimeTest = 0;
long testInterval = 5000;
//Format Bytes
String formatBytes(size_t bytes){
if(mySerial)
mySerial.println("formatBytes FUNC");
if (bytes < 1024){
return String(bytes)+"B";
} //end if
else if(bytes < (1024 * 1024)){
return String(bytes/1024.0)+"KB";
} //end else if
else if(bytes < (1024 * 1024 * 1024)){
return String(bytes/1024.0/1024.0)+"MB";
} //end else if
else {
return String(bytes/1024.0/1024.0/1024.0)+"GB";
} //end else
} //end function formatBytes
//Content Type for File System
String getContentType(String filename)
{
if(server.hasArg("download")) return "application/octet-stream";
else if(filename.endsWith(".htm")) return "text/html";
else if(filename.endsWith(".html")) return "text/html";
else if(filename.endsWith(".css")) return "text/css";
else if(filename.endsWith(".js")) return "application/javascript";
else if(filename.endsWith(".png")) return "image/png";
else if(filename.endsWith(".gif")) return "image/gif";
else if(filename.endsWith(".jpg")) return "image/jpeg";
else if(filename.endsWith(".ico")) return "image/x-icon";
else if(filename.endsWith(".xml")) return "text/xml";
else if(filename.endsWith(".pdf")) return "application/x-pdf";
else if(filename.endsWith(".zip")) return "application/x-zip";
else if(filename.endsWith(".gz")) return "application/x-gzip";
if(mySerial)
mySerial.println("getContentType FUNC");
return "text/plain";
} //end function getContentType
//File Read for File System
bool handleFileRead(String path)
{
if(mySerial)
mySerial.println("handleFileRead: " + path);
if(path.endsWith("/")) path += "index.htm";
String contentType = getContentType(path);
String pathWithGz = path + ".gz";
if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path))
{
if(SPIFFS.exists(pathWithGz))
path += ".gz";
File file = SPIFFS.open(path, "r");
if(mySerial)
mySerial.println("TEST: " + path + " FILE OPEN: " + file.size());
size_t sent = server.streamFile(file, contentType);
if(mySerial)
mySerial.println("TEST: " + path + " SIZE: " + file.size());
file.close();
if(mySerial)
mySerial.println("TEST: " + path + " FILE CLOSE");
return true;
} //end if
return false;
} //end function handleFileRead
//File Upload for File System
void handleFileUpload(){
if(server.uri() != "/edit") return;
HTTPUpload& upload = server.upload();
if(upload.status == UPLOAD_FILE_START)
{
String filename = upload.filename;
if(!filename.startsWith("/"))
filename = "/"+filename;
if(mySerial)
{
mySerial.print("handleFileUpload Name: ");
mySerial.println(filename);
} //end if
fsUploadFile = SPIFFS.open(filename, "w");
filename = String();
} //end if
else if(upload.status == UPLOAD_FILE_WRITE)
{
if(mySerial)
{
mySerial.print("handleFileUpload Data: ");
mySerial.println(upload.currentSize);
} //end if
if(fsUploadFile)
fsUploadFile.write(upload.buf, upload.currentSize);
} //end else if
else if(upload.status == UPLOAD_FILE_END)
{
if(fsUploadFile)
fsUploadFile.close();
if(mySerial)
{
mySerial.print("handleFileUpload Size: ");
mySerial.println(upload.totalSize);
} //end if
} //end else if
} //end function handleFileUpload
//File Delete for File System
void handleFileDelete()
{
if(server.args() == 0) return server.send(500, "text/plain", "BAD ARGS");
String path = server.arg(0);
if(mySerial)
mySerial.println("handleFileDelete: " + path);
if(path == "/")
return server.send(500, "text/plain", "BAD PATH");
if(!SPIFFS.exists(path))
return server.send(404, "text/plain", "FileNotFound");
SPIFFS.remove(path);
server.send(200, "text/plain", "");
path = String();
} //end function handleFileDelete
//File Create for File System
void handleFileCreate()
{
if(server.args() == 0)
return server.send(500, "text/plain", "BAD ARGS");
String path = server.arg(0);
if(mySerial)
mySerial.println("handleFileCreate: " + path);
if(path == "/")
return server.send(500, "text/plain", "BAD PATH");
if(SPIFFS.exists(path))
return server.send(500, "text/plain", "FILE EXISTS");
File file = SPIFFS.open(path, "w");
if(file)
file.close();
else
return server.send(500, "text/plain", "CREATE FAILED");
server.send(200, "text/plain", "");
path = String();
} //end function handleFileCreate
void handleFileList()
{
if(!server.hasArg("dir"))
{
server.send(500, "text/plain", "BAD ARGS");
return;
} //end if
String path = server.arg("dir");
if(mySerial)
mySerial.println("handleFileList: " + path);
Dir dir = SPIFFS.openDir(path);
path = String();
String output = "[";
while(dir.next())
{
File entry = dir.openFile("r");
if (output != "[") output += ',';
bool isDir = false;
output += "{\"type\":\"";
output += (isDir)?"dir":"file";
output += "\",\"name\":\"";
output += String(entry.name()).substring(1);
output += "\"}";
entry.close();
} //end while
output += "]";
server.send(200, "text/json", output);
} //end function handleFileList
//HHIO PTT POWER LED ON
void switchPOWERon() {
int powerStatusLength = 1;
subsys = SUBSYS_1;
//Account for the end of message
messageLength = powerStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
} //end switchPOWERon
//HHIO PTT POWER LED OFF
void switchPOWERoff() {
int powerStatusLength = 1;
subsys = SUBSYS_1;
//Account for the end of message
messageLength = powerStatusLength + 2;
messageContent = 0;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
} //end switchPOWERoff
//PUMP POWER ON
void pumpPOWERon() {
int pumpPowerStatusLength = 1;
subsys = SUBSYS_2;
//Account for the end of message
messageLength = pumpPowerStatusLength + 2;
messageContent = 1;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
} //end switchPOWERon
//PUMP POWER OFF
void pumpPOWERoff() {
int pumpPowerStatusLength = 1;
subsys = SUBSYS_2;
//Account for the end of message
messageLength = pumpPowerStatusLength + 2;
messageContent = 0;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
} //end switchPOWERoff
//LED POWER ON
void switchLEDon() {
int ledStatusLength = 1;
subsys = SUBSYS_3;
//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);
} //end switchLEDon
//LED POWER OFF
void switchLEDoff() {
int ledStatusLength = 1;
subsys = SUBSYS_3;
//Account for the end of message
messageLength = ledStatusLength + 2;
messageContent = 0;
Serial.write(som);
Serial.write(messageLength);
Serial.write(subsys);
Serial.write(messageContent);
Serial.write(eom);
} //end switchLEDoff
//Function to send all updated status values from arduino to the webpage
void statusUpdate(uint8_t num) {
//Valve C
if(currValveStatusNumC == 0)
{
valveColorC = "red";
valveTubePropsC = "175px solid #00ADEF";
valveStatusC = "Closed";
} //end if
else if(currValveStatusNumC == 1)
{
valveColorC = "green";
valveTubePropsC = "350px solid #00ADEF";
valveStatusC = "Open";
} //end else if
//Valve D
if(currValveStatusNumD == 0)
{
valveColorD = "red";
valveTubePropsD = "175px solid #00ADEF";
valveStatusD = "Closed";
} //end if
else if(currValveStatusNumD == 1)
{
valveColorD = "green";
valveTubePropsD = "350px solid #00ADEF";
valveStatusD = "Open";
} //end else if
//Valve E
if(currValveStatusNumE == 0)
{
valveColorE = "red";
valveTubePropsE = "175px solid #00ADEF";
valveStatusE = "Closed";
} //end if
else if(currValveStatusNumE == 1)
{
valveColorE = "green";
valveTubePropsE = "350px solid #00ADEF";
valveStatusE = "Open";
} //end else if
String test = "";
test += currNumRefresh;
test += ",";
test += currMicroC;
test += ",";
test += currMicroD;
test += ",";
test += currMicroE;
test += ",";
test += currPressureC;
test += ",";
test += currPressureD;
test += ",";
test += currPressureE;
test += ",";
test += valveColorC;
test += ",";
test += valveTubePropsC;
test += ",";
test += valveStatusC;
test += ",";
test += valveColorD;
test += ",";
test += valveTubePropsD;
test += ",";
test += valveStatusD;
test += ",";
test += valveColorE;
test += ",";
test += valveTubePropsE;
test += ",";
test += valveStatusE;
test += ",";
test += currFluid;
test.toCharArray(statusbuf, 256);
webSocket.sendTXT(num, statusbuf, strlen(statusbuf));
} //end function statusUpdate
// Current POWER status
bool POWERStatus;
// Current LED status
bool LEDStatus;
// Commands sent through Web Socket
const char LEDON[] = "ledon";
const char LEDOFF[] = "ledoff";
const char teensyPOWERON[] = "teensyPOWERon";
const char teensyPOWEROFF[] = "teensyPOWERoff";
const char pumpPOWERON[] = "pumpPOWERon";
const char pumpPOWEROFF[] = "pumpPOWERoff";
const char teensyLEDON[] = "teensyLEDon";
const char teensyLEDOFF[] = "teensyLEDoff";
const char statusIdentifier[] = "Update Status";
//Websocket Event Function
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
{
//if(mySerial)
//mySerial.printf("webSocketEvent(%d, %d, ...)\r\n", num, type);
switch(type) {
case WStype_DISCONNECTED:
//if(mySerial)
//mySerial.printf("[%u] Disconnected!\r\n", num);
break;
case WStype_CONNECTED:
{
IPAddress ip = webSocket.remoteIP(num);
//if(mySerial)
//mySerial.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
} //end case CONNECTED
break;
case WStype_TEXT:
//if(mySerial)
//mySerial.printf("[%u] get Text: %s\r\n", num, payload);
if(strcmp(teensyPOWERON, (const char *)payload) == 0) {
switchPOWERon();
} //end if
else if(strcmp(teensyPOWEROFF, (const char *)payload) == 0) {
switchPOWERoff();
} //end else if
else if(strcmp(pumpPOWERON, (const char *)payload) == 0) {
pumpPOWERon();
} //end else if
else if(strcmp(pumpPOWEROFF, (const char *)payload) == 0) {
pumpPOWERoff();
} //end else if
else if(strcmp(teensyLEDON, (const char *)payload) == 0) {
switchLEDon();
} //end else if
else if(strcmp(teensyLEDOFF, (const char *)payload) == 0) {
switchLEDoff();
} //end else if
else if(strcmp(statusIdentifier, (const char *)payload) == 0) {
statusUpdate(num);
} //end else if
else
{
if(mySerial)
mySerial.println("Unknown command");
} //end else
// send data to all connected clients
webSocket.broadcastTXT(payload, length);
break;
case WStype_BIN:
if(mySerial)
mySerial.printf("[%u] get binary length: %u\r\n", num, length);
hexdump(payload, length);
// echo data back to browser
webSocket.sendBIN(num, payload, length);
break;
default:
if(mySerial)
mySerial.printf("Invalid WStype [%d]\r\n", type);
break;
} //end switch
} //end function webSocketEvent
我还包含了jQuery和这个量表库:https://github.com/Mikhus/canv-gauge。
以下是SPIFFS服务器上的完整文件列表:
由于帖子大小限制,我没有包含HTML / CSS / JS;如果这有用,请告诉我,我会在回复中发布该代码。
答案 0 :(得分:2)
好吧所以我似乎通过使用修改后的库,压缩我的代码以及完全删除jQuery来解决这个问题。我偶尔会遇到错误,但这些似乎是不可避免的,一切都在大部分时间都有效。