// Defaulut is SPIFFS, FatFS: only on ESP32, also choose partition scheme w/ ffat. // Comment 2 lines below or uncomment only one of them //#define USE_LittleFS //#define USE_FatFS // Only ESP32 #include #ifdef ESP32 #include #ifdef USE_LittleFS #define MYFS LITTLEFS #include "LITTLEFS.h" #elif defined(USE_FatFS) #define MYFS FFat #include "FFat.h" #else #define MYFS SPIFFS #include #endif #include #include #include #elif defined(ESP8266) #ifdef USE_LittleFS #include #define MYFS LittleFS #include #elif defined(USE_FatFS) #error "FatFS only on ESP32 for now!" #else #define MYFS SPIFFS #endif #include #include #include #endif #include #include // SKETCH BEGIN AsyncWebServer server(80); AsyncWebSocket ws("/ws"); AsyncEventSource events("/events"); void onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t *data, size_t len){ if(type == WS_EVT_CONNECT){ Serial.printf("ws[%s][%u] connect\n", server->url(), client->id()); client->printf("Hello Client %u :)", client->id()); client->ping(); } else if(type == WS_EVT_DISCONNECT){ Serial.printf("ws[%s][%u] disconnect\n", server->url(), client->id()); } else if(type == WS_EVT_ERROR){ Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t*)arg), (char*)data); } else if(type == WS_EVT_PONG){ Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len)?(char*)data:""); } else if(type == WS_EVT_DATA){ AwsFrameInfo * info = (AwsFrameInfo*)arg; String msg = ""; 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 Serial.printf("ws[%s][%u] %s-message[%llu]: ", server->url(), client->id(), (info->opcode == WS_TEXT)?"text":"binary", info->len); if(info->opcode == WS_TEXT){ for(size_t i=0; i < info->len; i++) { msg += (char) data[i]; } } else { char buff[3]; for(size_t i=0; i < info->len; i++) { sprintf(buff, "%02x ", (uint8_t) data[i]); msg += buff ; } } Serial.printf("%s\n",msg.c_str()); 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) 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); } 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]; } } else { char buff[3]; for(size_t i=0; i < len; i++) { sprintf(buff, "%02x ", (uint8_t) data[i]); msg += buff ; } } Serial.printf("%s\n",msg.c_str()); if((info->index + len) == info->len){ Serial.printf("ws[%s][%u] frame[%u] end[%llu]\n", server->url(), client->id(), info->num, info->len); if(info->final){ Serial.printf("ws[%s][%u] %s-message end\n", server->url(), client->id(), (info->message_opcode == WS_TEXT)?"text":"binary"); 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 = "*****"; const char* hostName = "esp-async"; const char* http_username = "admin"; const char* http_password = "admin"; void setup(){ Serial.begin(115200); Serial.setDebugOutput(true); WiFi.mode(WIFI_AP_STA); WiFi.softAP(hostName); WiFi.begin(ssid, password); if (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.printf("STA: Failed!\n"); WiFi.disconnect(false); delay(1000); WiFi.begin(ssid, password); } Serial.print(F("*CONNECTED* IP:")); Serial.println(WiFi.localIP()); //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"); }); ArduinoOTA.setHostname(hostName); ArduinoOTA.begin(); MDNS.addService("http","tcp",80); //FS #ifdef USE_FatFS if (MYFS.begin(false,"/ffat",3)) { //limit the RAM usage, bottom line 8kb + 4kb takes per each file, default is 10 #else if (MYFS.begin()) { #endif Serial.print(F("FS mounted\n")); } else { Serial.print(F("FS mount failed\n")); } ws.onEvent(onWsEvent); server.addHandler(&ws); events.onConnect([](AsyncEventSourceClient *client){ client->send("hello!",NULL,millis(),1000); }); server.addHandler(&events); #ifdef ESP32 server.addHandler(new SPIFFSEditor(MYFS, http_username,http_password)); #elif defined(ESP8266) server.addHandler(new SPIFFSEditor(http_username,http_password, MYFS)); #endif server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/plain", String(ESP.getFreeHeap())); }); server.serveStatic("/", MYFS, "/").setDefaultFile("index.htm"); server.onNotFound([](AsyncWebServerRequest *request){ Serial.printf("NOT_FOUND: "); if(request->method() == HTTP_GET) Serial.printf("GET"); else if(request->method() == HTTP_POST) Serial.printf("POST"); else if(request->method() == HTTP_DELETE) Serial.printf("DELETE"); else if(request->method() == HTTP_PUT) Serial.printf("PUT"); else if(request->method() == HTTP_PATCH) Serial.printf("PATCH"); else if(request->method() == HTTP_HEAD) Serial.printf("HEAD"); else if(request->method() == HTTP_OPTIONS) Serial.printf("OPTIONS"); else Serial.printf("UNKNOWN"); Serial.printf(" http://%s%s\n", request->host().c_str(), request->url().c_str()); if(request->contentLength()){ Serial.printf("_CONTENT_TYPE: %s\n", request->contentType().c_str()); Serial.printf("_CONTENT_LENGTH: %u\n", request->contentLength()); } int headers = request->headers(); int i; for(i=0;igetHeader(i); Serial.printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str()); } int params = request->params(); for(i=0;igetParam(i); if(p->isFile()){ Serial.printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size()); } else if(p->isPost()){ Serial.printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); } else { Serial.printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } } request->send(404); }); server.onFileUpload([](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final){ if(!index) Serial.printf("UploadStart: %s\n", filename.c_str()); Serial.printf("%s", (const char*)data); if(final) Serial.printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len); }); server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){ if(!index) Serial.printf("BodyStart: %u\n", total); Serial.printf("%s", (const char*)data); if(index + len == total) Serial.printf("BodyEnd: %u\n", total); }); server.begin(); } void loop(){ ArduinoOTA.handle(); ws.cleanupClients(); }