ESPAsyncWebServer/examples/ESP_AsyncFSBrowser/ESP_AsyncFSBrowser.ino

222 lines
7.6 KiB
Arduino
Raw Normal View History

2015-12-19 10:05:59 -08:00
#include <ArduinoOTA.h>
#ifdef ESP32
2015-12-19 10:05:59 -08:00
#include <FS.h>
#include <SPIFFS.h>
#include <ESPmDNS.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESP8266mDNS.h>
#endif
2015-12-19 10:05:59 -08:00
#include <ESPAsyncWebServer.h>
2016-09-23 05:11:50 -07:00
#include <SPIFFSEditor.h>
2015-12-19 10:05:59 -08:00
// SKETCH BEGIN
AsyncWebServer server(80);
2016-04-23 05:11:32 -07:00
AsyncWebSocket ws("/ws");
AsyncEventSource events("/events");
2016-04-23 05:11:32 -07:00
void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){
2016-04-23 05:11:32 -07:00
if(type == WS_EVT_CONNECT){
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
2016-04-23 05:11:32 -07:00
client->printf("Hello Client %u :)", client->id());
client->ping();
} else if(type == WS_EVT_DISCONNECT){
2019-10-02 00:32:15 -07:00
Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id());
2016-04-23 05:11:32 -07:00
} else if(type == WS_EVT_ERROR){
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data);
2016-04-23 05:11:32 -07:00
} else if(type == WS_EVT_PONG){
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:"");
2016-04-23 05:11:32 -07:00
} else if(type == WS_EVT_DATA){
AwsFrameInfo * info = (AwsFrameInfo*)arg;
String msg = "";
2016-04-23 05:11:32 -07:00
if(info->final && info->index == 0 && info->len == len){
//the whole message is in a single frame and we got all of it's data
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len);
2016-04-23 05:11:32 -07:00
if(info->opcode == WS_TEXT){
for(size_t i=0; i < info->len; i++) {
msg += (char) data[i];
}
2016-04-23 05:11:32 -07:00
} else {
char buff[3];
for(size_t i=0; i < info->len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
2016-04-23 05:11:32 -07:00
}
}
2016-08-27 07:32:51 -07:00
Serial.printf("%s\n",msg.c_str());
2016-04-23 05:11:32 -07:00
if(info->opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
} else {
//message is comprised of multiple frames or the frame is split into multiple packets
if(info->index == 0){
if(info->num == 0)
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] %s-message start\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
Serial.printf("ws[%s][%u] frame[%u] start[%llu]\n", server->url(), client->id(), info->num, info->len);
2016-04-23 05:11:32 -07:00
}
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT)?"text":"binary", info->index, info->index + len);
if(info->opcode == WS_TEXT){
for(size_t i=0; i < len; i++) {
msg += (char) data[i];
}
2016-04-23 05:11:32 -07:00
} else {
char buff[3];
for(size_t i=0; i < len; i++) {
sprintf(buff, "%02x ", (uint8_t) data[i]);
msg += buff ;
2016-04-23 05:11:32 -07:00
}
}
2016-08-27 07:32:51 -07:00
Serial.printf("%s\n",msg.c_str());
2016-04-23 05:11:32 -07:00
if((info->index + len) == info->len){
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len);
2016-04-23 05:11:32 -07:00
if(info->final){
2016-08-27 07:32:51 -07:00
Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary");
2016-04-23 05:11:32 -07:00
if(info->message_opcode == WS_TEXT)
client->text("I got your text message");
else
client->binary("I got your binary message");
}
}
}
}
}
const char* ssid = "*******";
const char* password = "*******";
2016-08-27 07:32:51 -07:00
const char * hostName = "esp-async";
2015-12-19 10:05:59 -08:00
const char* http_username = "admin";
const char* http_password = "admin";
void setup(){
Serial.begin(115200);
Serial.setDebugOutput(true);
2016-08-27 07:32:51 -07:00
WiFi.mode(WIFI_AP_STA);
WiFi.softAP(hostName);
2015-12-19 10:05:59 -08:00
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("STA: Failed!\n");
WiFi.disconnect(false);
delay(1000);
WiFi.begin(ssid, password);
}
//Send OTA events to the browser
ArduinoOTA.onStart([]() { events.send("Update Start", "ota"); });
ArduinoOTA.onEnd([]() { events.send("Update End", "ota"); });
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
char p[32];
sprintf(p, "Progress: %u%%\n", (progress/(total/100)));
events.send(p, "ota");
});
ArduinoOTA.onError([](ota_error_t error) {
if(error == OTA_AUTH_ERROR) events.send("Auth Failed", "ota");
else if(error == OTA_BEGIN_ERROR) events.send("Begin Failed", "ota");
else if(error == OTA_CONNECT_ERROR) events.send("Connect Failed", "ota");
else if(error == OTA_RECEIVE_ERROR) events.send("Recieve Failed", "ota");
else if(error == OTA_END_ERROR) events.send("End Failed", "ota");
});
2016-08-27 07:32:51 -07:00
ArduinoOTA.setHostname(hostName);
2015-12-19 10:05:59 -08:00
ArduinoOTA.begin();
2016-08-27 07:32:51 -07:00
MDNS.addService("http","tcp",80);
SPIFFS.begin();
ws.onEvent(onWsEvent);
2016-04-23 05:11:32 -07:00
server.addHandler(&ws);
events.onConnect([](AsyncEventSourceClient *client){
client->send("hello!",NULL,millis(),1000);
});
server.addHandler(&events);
#ifdef ESP32
server.addHandler(new SPIFFSEditor(SPIFFS, http_username,http_password));
#elif defined(ESP8266)
server.addHandler(new SPIFFSEditor(http_username,http_password));
#endif
2015-12-19 10:05:59 -08:00
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/plain", String(ESP.getFreeHeap()));
});
2016-08-27 07:32:51 -07:00
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.htm");
2015-12-19 10:05:59 -08:00
server.onNotFound([](AsyncWebServerRequest *request){
2016-08-27 07:32:51 -07:00
Serial.printf("NOT_FOUND: ");
2015-12-19 10:05:59 -08:00
if(request->method() == HTTP_GET)
2016-08-27 07:32:51 -07:00
Serial.printf("GET");
2015-12-19 10:05:59 -08:00
else if(request->method() == HTTP_POST)
2016-08-27 07:32:51 -07:00
Serial.printf("POST");
2015-12-19 10:05:59 -08:00
else if(request->method() == HTTP_DELETE)
2016-08-27 07:32:51 -07:00
Serial.printf("DELETE");
2015-12-19 10:05:59 -08:00
else if(request->method() == HTTP_PUT)
2016-08-27 07:32:51 -07:00
Serial.printf("PUT");
2015-12-19 10:05:59 -08:00
else if(request->method() == HTTP_PATCH)
2016-08-27 07:32:51 -07:00
Serial.printf("PATCH");
2015-12-19 10:05:59 -08:00
else if(request->method() == HTTP_HEAD)
2016-08-27 07:32:51 -07:00
Serial.printf("HEAD");
2015-12-19 10:05:59 -08:00
else if(request->method() == HTTP_OPTIONS)
2016-08-27 07:32:51 -07:00
Serial.printf("OPTIONS");
2015-12-19 10:05:59 -08:00
else
2016-08-27 07:32:51 -07:00
Serial.printf("UNKNOWN");
Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());
2015-12-19 10:05:59 -08:00
if(request->contentLength()){
2016-08-27 07:32:51 -07:00
Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength());
2015-12-19 10:05:59 -08:00
}
int headers = request->headers();
int i;
for(i=0;i<headers;i++){
AsyncWebHeader* h = request->getHeader(i);
2016-08-27 07:32:51 -07:00
Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
2015-12-19 10:05:59 -08:00
}
int params = request->params();
for(i=0;i<params;i++){
AsyncWebParameter* p = request->getParam(i);
if(p->isFile()){
2016-08-27 07:32:51 -07:00
Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
2015-12-19 10:05:59 -08:00
} else if(p->isPost()){
2016-08-27 07:32:51 -07:00
Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
2015-12-19 10:05:59 -08:00
} else {
2016-08-27 07:32:51 -07:00
Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
2015-12-19 10:05:59 -08:00
}
}
request->send(404);
});
server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){
2015-12-19 10:05:59 -08:00
if(!index)
2016-08-27 07:32:51 -07:00
Serial.printf("UploadStart: %s\n", filename.c_str());
Serial.printf("%s", (const char*)data);
2015-12-19 10:05:59 -08:00
if(final)
2016-08-27 07:32:51 -07:00
Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len);
2015-12-19 10:05:59 -08:00
});
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
if(!index)
2016-08-27 07:32:51 -07:00
Serial.printf("BodyStart: %u\n", total);
Serial.printf("%s", (const char*)data);
2015-12-19 10:05:59 -08:00
if(index + len == total)
2016-08-27 07:32:51 -07:00
Serial.printf("BodyEnd: %u\n", total);
2015-12-19 10:05:59 -08:00
});
server.begin();
}
void loop(){
ArduinoOTA.handle();
Add function so that the total number of web-socket clients can be limited (#591) * Add function so that the total number of web-socket clients can be limited easily. This is to cope with a problem when a browser does not close the web-socket connection correctly. I have observed this on Chromium based browsers. The memory leak will eventually lead to the server crashing. Normally only one connection per client is required, so limiting the number of connections would not normally cause any problems. * Prevent an assertion failure when using WebSockets Frequently when using Web Sockets you will get the assert failure: assertion "new_rcv_ann_wnd <= 0xffff" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/lwip/lwip/src/core/tcp.c", line 779, function: tcp_update_rcv_ann_wnd This will happen particulary when you close the browser window. This change prevents the issue from occuring. * Do not use thread locking with the ESP8266, but instead use an empty placeholder class that can be used to implement locking at a later date. * Do not use thread locking with the ESP8266, but instead use an empty placeholder class that can be used to implement locking at a later date. * Add function so that the total number of web-socket clients can be limited easily. This is to cope with a problem when a browser does not close the web-socket connection correctly. I have observed this on Chromium based browsers. The memory leak will eventually lead to the server crashing. Normally only one connection per client is required, so limiting the number of connections would not normally cause any problems. * Set the default number of ws clients dependent on processor.
2019-09-24 12:42:40 -07:00
ws.cleanupClients();
2015-12-19 10:05:59 -08:00
}