--- /dev/null
+/* HTTP File Server Example
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include "esp_err.h"
+#include "esp_log.h"
+
+#include "esp_vfs.h"
+#include "esp_spiffs.h"
+#include "esp_http_server.h"
+
+/* Max length a file path can have on storage */
+#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN)
+
+/* Max size of an individual file. Make sure this
+ * value is same as that set in upload_script.html */
+#define MAX_FILE_SIZE (200*1024) // 200 KB
+#define MAX_FILE_SIZE_STR "200KB"
+
+/* Scratch buffer size */
+#define SCRATCH_BUFSIZE 8192
+
+struct file_server_data {
+ /* Base path of file storage */
+ char base_path[ESP_VFS_PATH_MAX + 1];
+
+ /* Scratch buffer for temporary storage during file transfer */
+ char scratch[SCRATCH_BUFSIZE];
+};
+
+static const char *TAG = "file_server";
+
+/* Handler to redirect incoming GET request for /index.html to / */
+static esp_err_t index_html_get_handler(httpd_req_t *req)
+{
+ httpd_resp_set_status(req, "301 Permanent Redirect");
+ httpd_resp_set_hdr(req, "Location", "/");
+ httpd_resp_send(req, NULL, 0); // Response body can be empty
+ return ESP_OK;
+}
+
+/* Send HTTP response with a run-time generated html consisting of
+ * a list of all files and folders under the requested path */
+static esp_err_t http_resp_dir_html(httpd_req_t *req)
+{
+ char fullpath[FILE_PATH_MAX];
+ char entrysize[16];
+ const char *entrytype;
+
+ DIR *dir = NULL;
+ struct dirent *entry;
+ struct stat entry_stat;
+
+ /* Retrieve the base path of file storage to construct the full path */
+ strcpy(fullpath, ((struct file_server_data *)req->user_ctx)->base_path);
+
+ /* Concatenate the requested directory path */
+ strcat(fullpath, req->uri);
+ dir = opendir(fullpath);
+ const size_t entrypath_offset = strlen(fullpath);
+
+ if (!dir) {
+ /* If opening directory failed then send 404 server error */
+ httpd_resp_send_404(req);
+ return ESP_OK;
+ }
+
+ /* Send HTML file header */
+ httpd_resp_sendstr_chunk(req, "<!DOCTYPE html><html><body>");
+
+ /* Get handle to embedded file upload script */
+ extern const unsigned char upload_script_start[] asm("_binary_upload_script_html_start");
+ extern const unsigned char upload_script_end[] asm("_binary_upload_script_html_end");
+ const size_t upload_script_size = (upload_script_end - upload_script_start);
+
+ /* Add file upload form and script which on execution sends a POST request to /upload */
+ httpd_resp_send_chunk(req, (const char *)upload_script_start, upload_script_size);
+
+ /* Send file-list table definition and column labels */
+ httpd_resp_sendstr_chunk(req,
+ "<table class=\"fixed\" border=\"1\">"
+ "<col width=\"800px\" /><col width=\"300px\" /><col width=\"300px\" /><col width=\"100px\" />"
+ "<thead><tr><th>Name</th><th>Type</th><th>Size (Bytes)</th><th>Delete</th></tr></thead>"
+ "<tbody>");
+
+ /* Iterate over all files / folders and fetch their names and sizes */
+ while ((entry = readdir(dir)) != NULL) {
+ entrytype = (entry->d_type == DT_DIR ? "directory" : "file");
+
+ strncpy(fullpath + entrypath_offset, entry->d_name, sizeof(fullpath) - entrypath_offset);
+ if (stat(fullpath, &entry_stat) == -1) {
+ ESP_LOGE(TAG, "Failed to stat %s : %s", entrytype, entry->d_name);
+ continue;
+ }
+ sprintf(entrysize, "%ld", entry_stat.st_size);
+ ESP_LOGI(TAG, "Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize);
+
+ /* Send chunk of HTML file containing table entries with file name and size */
+ httpd_resp_sendstr_chunk(req, "<tr><td><a href=\"");
+ httpd_resp_sendstr_chunk(req, req->uri);
+ httpd_resp_sendstr_chunk(req, entry->d_name);
+ if (entry->d_type == DT_DIR) {
+ httpd_resp_sendstr_chunk(req, "/");
+ }
+ httpd_resp_sendstr_chunk(req, "\">");
+ httpd_resp_sendstr_chunk(req, entry->d_name);
+ httpd_resp_sendstr_chunk(req, "</a></td><td>");
+ httpd_resp_sendstr_chunk(req, entrytype);
+ httpd_resp_sendstr_chunk(req, "</td><td>");
+ httpd_resp_sendstr_chunk(req, entrysize);
+ httpd_resp_sendstr_chunk(req, "</td><td>");
+ httpd_resp_sendstr_chunk(req, "<form method=\"post\" action=\"/delete");
+ httpd_resp_sendstr_chunk(req, req->uri);
+ httpd_resp_sendstr_chunk(req, entry->d_name);
+ httpd_resp_sendstr_chunk(req, "\"><button type=\"submit\">Delete</button></form>");
+ httpd_resp_sendstr_chunk(req, "</td></tr>\n");
+ }
+ closedir(dir);
+
+ /* Finish the file list table */
+ httpd_resp_sendstr_chunk(req, "</tbody></table>");
+
+ /* Send remaining chunk of HTML file to complete it */
+ httpd_resp_sendstr_chunk(req, "</body></html>");
+
+ /* Send empty chunk to signal HTTP response completion */
+ httpd_resp_sendstr_chunk(req, NULL);
+ return ESP_OK;
+}
+
+#define IS_FILE_EXT(filename, ext) \
+ (strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0)
+
+/* Set HTTP response content type according to file extension */
+static esp_err_t set_content_type_from_file(httpd_req_t *req)
+{
+ if (IS_FILE_EXT(req->uri, ".pdf")) {
+ return httpd_resp_set_type(req, "application/pdf");
+ } else if (IS_FILE_EXT(req->uri, ".html")) {
+ return httpd_resp_set_type(req, "text/html");
+ } else if (IS_FILE_EXT(req->uri, ".jpeg")) {
+ return httpd_resp_set_type(req, "image/jpeg");
+ }
+ /* This is a limited set only */
+ /* For any other type always set as plain text */
+ return httpd_resp_set_type(req, "text/plain");
+}
+
+/* Send HTTP response with the contents of the requested file */
+static esp_err_t http_resp_file(httpd_req_t *req)
+{
+ char filepath[FILE_PATH_MAX];
+ FILE *fd = NULL;
+ struct stat file_stat;
+
+ /* Retrieve the base path of file storage to construct the full path */
+ strcpy(filepath, ((struct file_server_data *)req->user_ctx)->base_path);
+
+ /* Concatenate the requested file path */
+ strcat(filepath, req->uri);
+ if (stat(filepath, &file_stat) == -1) {
+ ESP_LOGE(TAG, "Failed to stat file : %s", filepath);
+ /* If file doesn't exist respond with 404 Not Found */
+ httpd_resp_send_404(req);
+ return ESP_OK;
+ }
+
+ fd = fopen(filepath, "r");
+ if (!fd) {
+ ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
+ /* If file exists but unable to open respond with 500 Server Error */
+ httpd_resp_set_status(req, "500 Server Error");
+ httpd_resp_sendstr(req, "Failed to read existing file!");
+ return ESP_OK;
+ }
+
+ ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filepath, file_stat.st_size);
+ set_content_type_from_file(req);
+
+ /* Retrieve the pointer to scratch buffer for temporary storage */
+ char *chunk = ((struct file_server_data *)req->user_ctx)->scratch;
+ size_t chunksize;
+ do {
+ /* Read file in chunks into the scratch buffer */
+ chunksize = fread(chunk, 1, SCRATCH_BUFSIZE, fd);
+
+ /* Send the buffer contents as HTTP response chunk */
+ if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
+ fclose(fd);
+ ESP_LOGE(TAG, "File sending failed!");
+ /* Abort sending file */
+ httpd_resp_sendstr_chunk(req, NULL);
+ /* Send error message with status code */
+ httpd_resp_set_status(req, "500 Server Error");
+ httpd_resp_sendstr(req, "Failed to send file!");
+ return ESP_OK;
+ }
+
+ /* Keep looping till the whole file is sent */
+ } while (chunksize != 0);
+
+ /* Close file after sending complete */
+ fclose(fd);
+ ESP_LOGI(TAG, "File sending complete");
+
+ /* Respond with an empty chunk to signal HTTP response completion */
+ httpd_resp_send_chunk(req, NULL, 0);
+ return ESP_OK;
+}
+
+/* Handler to download a file kept on the server */
+static esp_err_t download_get_handler(httpd_req_t *req)
+{
+ // Check if the target is a directory
+ if (req->uri[strlen(req->uri) - 1] == '/') {
+ // In so, send an html with directory listing
+ http_resp_dir_html(req);
+ } else {
+ // Else send the file
+ http_resp_file(req);
+ }
+ return ESP_OK;
+}
+
+/* Handler to upload a file onto the server */
+static esp_err_t upload_post_handler(httpd_req_t *req)
+{
+ char filepath[FILE_PATH_MAX];
+ FILE *fd = NULL;
+ struct stat file_stat;
+
+ /* Skip leading "/upload" from URI to get filename */
+ /* Note sizeof() counts NULL termination hence the -1 */
+ const char *filename = req->uri + sizeof("/upload") - 1;
+
+ /* Filename cannot be empty or have a trailing '/' */
+ if (strlen(filename) == 0 || filename[strlen(filename) - 1] == '/') {
+ ESP_LOGE(TAG, "Invalid file name : %s", filename);
+ /* Respond with 400 Bad Request */
+ httpd_resp_set_status(req, "400 Bad Request");
+ /* Send failure reason */
+ httpd_resp_sendstr(req, "Invalid file name!");
+ return ESP_OK;
+ }
+
+ /* Retrieve the base path of file storage to construct the full path */
+ strcpy(filepath, ((struct file_server_data *)req->user_ctx)->base_path);
+
+ /* Concatenate the requested file path */
+ strcat(filepath, filename);
+ if (stat(filepath, &file_stat) == 0) {
+ ESP_LOGE(TAG, "File already exists : %s", filepath);
+ /* If file exists respond with 400 Bad Request */
+ httpd_resp_set_status(req, "400 Bad Request");
+ httpd_resp_sendstr(req, "File already exists!");
+ return ESP_OK;
+ }
+
+ /* File cannot be larger than a limit */
+ if (req->content_len > MAX_FILE_SIZE) {
+ ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
+ httpd_resp_set_status(req, "400 Bad Request");
+ httpd_resp_sendstr(req, "File size must be less than "
+ MAX_FILE_SIZE_STR "!");
+ /* Return failure to close underlying connection else the
+ * incoming file content will keep the socket busy */
+ return ESP_FAIL;
+ }
+
+ fd = fopen(filepath, "w");
+ if (!fd) {
+ ESP_LOGE(TAG, "Failed to create file : %s", filepath);
+ /* If file creation failed, respond with 500 Server Error */
+ httpd_resp_set_status(req, "500 Server Error");
+ httpd_resp_sendstr(req, "Failed to create file!");
+ return ESP_OK;
+ }
+
+ ESP_LOGI(TAG, "Receiving file : %s...", filename);
+
+ /* Retrieve the pointer to scratch buffer for temporary storage */
+ char *buf = ((struct file_server_data *)req->user_ctx)->scratch;
+ int received;
+
+ /* Content length of the request gives
+ * the size of the file being uploaded */
+ int remaining = req->content_len;
+
+ while (remaining > 0) {
+
+ ESP_LOGI(TAG, "Remaining size : %d", remaining);
+ /* Receive the file part by part into a buffer */
+ if ((received = httpd_req_recv(req, buf, MIN(remaining, SCRATCH_BUFSIZE))) <= 0) {
+ if (received == HTTPD_SOCK_ERR_TIMEOUT) {
+ /* Retry if timeout occurred */
+ continue;
+ }
+
+ /* In case of unrecoverable error,
+ * close and delete the unfinished file*/
+ fclose(fd);
+ unlink(filepath);
+
+ ESP_LOGE(TAG, "File reception failed!");
+ /* Return failure reason with status code */
+ httpd_resp_set_status(req, "500 Server Error");
+ httpd_resp_sendstr(req, "Failed to receive file!");
+ return ESP_OK;
+ }
+
+ /* Write buffer content to file on storage */
+ if (received && (received != fwrite(buf, 1, received, fd))) {
+ /* Couldn't write everything to file!
+ * Storage may be full? */
+ fclose(fd);
+ unlink(filepath);
+
+ ESP_LOGE(TAG, "File write failed!");
+ httpd_resp_set_status(req, "500 Server Error");
+ httpd_resp_sendstr(req, "Failed to write file to storage!");
+ return ESP_OK;
+ }
+
+ /* Keep track of remaining size of
+ * the file left to be uploaded */
+ remaining -= received;
+ }
+
+ /* Close file upon upload completion */
+ fclose(fd);
+ ESP_LOGI(TAG, "File reception complete");
+
+ /* Redirect onto root to see the updated file list */
+ httpd_resp_set_status(req, "303 See Other");
+ httpd_resp_set_hdr(req, "Location", "/");
+ httpd_resp_sendstr(req, "File uploaded successfully");
+ return ESP_OK;
+}
+
+/* Handler to delete a file from the server */
+static esp_err_t delete_post_handler(httpd_req_t *req)
+{
+ char filepath[FILE_PATH_MAX];
+ struct stat file_stat;
+
+ /* Skip leading "/upload" from URI to get filename */
+ /* Note sizeof() counts NULL termination hence the -1 */
+ const char *filename = req->uri + sizeof("/upload") - 1;
+
+ /* Filename cannot be empty or have a trailing '/' */
+ if (strlen(filename) == 0 || filename[strlen(filename) - 1] == '/') {
+ ESP_LOGE(TAG, "Invalid file name : %s", filename);
+ /* Respond with 400 Bad Request */
+ httpd_resp_set_status(req, "400 Bad Request");
+ /* Send failure reason */
+ httpd_resp_sendstr(req, "Invalid file name!");
+ return ESP_OK;
+ }
+
+ /* Retrieve the base path of file storage to construct the full path */
+ strcpy(filepath, ((struct file_server_data *)req->user_ctx)->base_path);
+
+ /* Concatenate the requested file path */
+ strcat(filepath, filename);
+ if (stat(filepath, &file_stat) == -1) {
+ ESP_LOGE(TAG, "File does not exist : %s", filename);
+ /* If file does not exist respond with 400 Bad Request */
+ httpd_resp_set_status(req, "400 Bad Request");
+ httpd_resp_sendstr(req, "File does not exist!");
+ return ESP_OK;
+ }
+
+ ESP_LOGI(TAG, "Deleting file : %s", filename);
+ /* Delete file */
+ unlink(filepath);
+
+ /* Redirect onto root to see the updated file list */
+ httpd_resp_set_status(req, "303 See Other");
+ httpd_resp_set_hdr(req, "Location", "/");
+ httpd_resp_sendstr(req, "File deleted successfully");
+ return ESP_OK;
+}
+
+/* Handler to respond with an icon file embedded in flash.
+ * Browsers expect to GET website icon at URI /favicon.ico */
+static esp_err_t favicon_get_handler(httpd_req_t *req)
+{
+ extern const unsigned char favicon_ico_start[] asm("_binary_favicon_ico_start");
+ extern const unsigned char favicon_ico_end[] asm("_binary_favicon_ico_end");
+ const size_t favicon_ico_size = (favicon_ico_end - favicon_ico_start);
+ httpd_resp_set_type(req, "image/x-icon");
+ httpd_resp_send(req, (const char *)favicon_ico_start, favicon_ico_size);
+ return ESP_OK;
+}
+
+/* Function to start the file server */
+esp_err_t start_file_server(const char *base_path)
+{
+ static struct file_server_data *server_data = NULL;
+
+ /* Validate file storage base path */
+ if (!base_path || strcmp(base_path, "/spiffs") != 0) {
+ ESP_LOGE(TAG, "File server presently supports only '/spiffs' as base path");
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ if (server_data) {
+ ESP_LOGE(TAG, "File server already started");
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ /* Allocate memory for server data */
+ server_data = calloc(1, sizeof(struct file_server_data));
+ if (!server_data) {
+ ESP_LOGE(TAG, "Failed to allocate memory for server data");
+ return ESP_ERR_NO_MEM;
+ }
+ strlcpy(server_data->base_path, base_path,
+ sizeof(server_data->base_path));
+
+ httpd_handle_t server = NULL;
+ httpd_config_t config = HTTPD_DEFAULT_CONFIG();
+
+ /* Use the URI wildcard matching function in order to
+ * allow the same handler to respond to multiple different
+ * target URIs which match the wildcard scheme */
+ config.uri_match_fn = httpd_uri_match_wildcard;
+
+ ESP_LOGI(TAG, "Starting HTTP Server");
+ if (httpd_start(&server, &config) != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to start file server!");
+ return ESP_FAIL;
+ }
+
+ /* Register handler for index.html which should redirect to / */
+ httpd_uri_t index_html = {
+ .uri = "/index.html",
+ .method = HTTP_GET,
+ .handler = index_html_get_handler,
+ .user_ctx = NULL
+ };
+ httpd_register_uri_handler(server, &index_html);
+
+ /* Handler for URI used by browsers to get website icon */
+ httpd_uri_t favicon_ico = {
+ .uri = "/favicon.ico",
+ .method = HTTP_GET,
+ .handler = favicon_get_handler,
+ .user_ctx = NULL
+ };
+ httpd_register_uri_handler(server, &favicon_ico);
+
+ /* URI handler for getting uploaded files */
+ httpd_uri_t file_download = {
+ .uri = "/*", // Match all URIs of type /path/to/file (except index.html)
+ .method = HTTP_GET,
+ .handler = download_get_handler,
+ .user_ctx = server_data // Pass server data as context
+ };
+ httpd_register_uri_handler(server, &file_download);
+
+ /* URI handler for uploading files to server */
+ httpd_uri_t file_upload = {
+ .uri = "/upload/*", // Match all URIs of type /upload/path/to/file
+ .method = HTTP_POST,
+ .handler = upload_post_handler,
+ .user_ctx = server_data // Pass server data as context
+ };
+ httpd_register_uri_handler(server, &file_upload);
+
+ /* URI handler for deleting files from server */
+ httpd_uri_t file_delete = {
+ .uri = "/delete/*", // Match all URIs of type /delete/path/to/file
+ .method = HTTP_POST,
+ .handler = delete_post_handler,
+ .user_ctx = server_data // Pass server data as context
+ };
+ httpd_register_uri_handler(server, &file_delete);
+
+ return ESP_OK;
+}
--- /dev/null
+/* HTTP File Server Example
+
+ This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+ Unless required by applicable law or agreed to in writing, this
+ software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <sys/param.h>
+
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+#include "esp_log.h"
+#include "esp_system.h"
+#include "esp_spiffs.h"
+#include "nvs_flash.h"
+
+/* This example demonstrates how to create file server
+ * using esp_http_server. This file has only startup code.
+ * Look in file_server.c for the implementation */
+
+/* The example uses simple WiFi configuration that you can set via
+ * 'make menuconfig'.
+ * If you'd rather not, just change the below entries to strings
+ * with the config you want -
+ * ie. #define EXAMPLE_WIFI_SSID "mywifissid"
+*/
+#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
+#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
+
+static const char *TAG="example";
+
+/* Wi-Fi event handler */
+static esp_err_t event_handler(void *ctx, system_event_t *event)
+{
+ switch(event->event_id) {
+ case SYSTEM_EVENT_STA_START:
+ ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
+ ESP_ERROR_CHECK(esp_wifi_connect());
+ break;
+ case SYSTEM_EVENT_STA_GOT_IP:
+ ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
+ ESP_LOGI(TAG, "Got IP: '%s'",
+ ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
+ break;
+ case SYSTEM_EVENT_STA_DISCONNECTED:
+ ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
+ ESP_ERROR_CHECK(esp_wifi_connect());
+ break;
+ default:
+ break;
+ }
+ return ESP_OK;
+}
+
+/* Function to initialize Wi-Fi at station */
+static void initialise_wifi(void)
+{
+ ESP_ERROR_CHECK(nvs_flash_init());
+ tcpip_adapter_init();
+ ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
+ wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+ ESP_ERROR_CHECK(esp_wifi_init(&cfg));
+ ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
+ wifi_config_t wifi_config = {
+ .sta = {
+ .ssid = EXAMPLE_WIFI_SSID,
+ .password = EXAMPLE_WIFI_PASS,
+ },
+ };
+ ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
+ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
+ ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
+ ESP_ERROR_CHECK(esp_wifi_start());
+}
+
+/* Function to initialize SPIFFS */
+static esp_err_t init_spiffs(void)
+{
+ ESP_LOGI(TAG, "Initializing SPIFFS");
+
+ esp_vfs_spiffs_conf_t conf = {
+ .base_path = "/spiffs",
+ .partition_label = NULL,
+ .max_files = 5, // This decides the maximum number of files that can be created on the storage
+ .format_if_mount_failed = true
+ };
+
+ esp_err_t ret = esp_vfs_spiffs_register(&conf);
+ if (ret != ESP_OK) {
+ if (ret == ESP_FAIL) {
+ ESP_LOGE(TAG, "Failed to mount or format filesystem");
+ } else if (ret == ESP_ERR_NOT_FOUND) {
+ ESP_LOGE(TAG, "Failed to find SPIFFS partition");
+ } else {
+ ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
+ }
+ return ESP_FAIL;
+ }
+
+ size_t total = 0, used = 0;
+ ret = esp_spiffs_info(NULL, &total, &used);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
+ return ESP_FAIL;
+ }
+
+ ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
+ return ESP_OK;
+}
+
+/* Declare the function which starts the file server.
+ * Implementation of this function is to be found in
+ * file_server.c */
+esp_err_t start_file_server(const char *base_path);
+
+void app_main()
+{
+ initialise_wifi();
+
+ /* Initialize file storage */
+ ESP_ERROR_CHECK(init_spiffs());
+
+ /* Start the file server */
+ ESP_ERROR_CHECK(start_file_server("/spiffs"));
+}