34 #include <sys/param.h>
35 #include <sys/unistd.h>
42 #include "esp_spiffs.h"
43 #include "esp_http_server.h"
46 static const char *
TAG = CONFIG_WEBSERVER_LOG_TAG;
49 #define FILE_PATH_MAX (ESP_VFS_PATH_MAX + CONFIG_SPIFFS_OBJ_NAME_LEN)
53 #define MAX_FILE_SIZE (200 * 1024)
54 #define MAX_FILE_SIZE_STR "200KB"
57 #define SCRATCH_BUFSIZE 8192
71 static const char *get_path_from_uri(
char *dest,
const char *base_path,
const char *uri,
size_t destsize)
73 const size_t base_pathlen = strlen(base_path);
74 size_t pathlen = strlen(uri);
76 const char *quest = strchr(uri,
'?');
79 pathlen = MIN(pathlen, quest - uri);
81 const char *hash = strchr(uri,
'#');
84 pathlen = MIN(pathlen, hash - uri);
87 if (base_pathlen + pathlen + 1 > destsize)
94 strcpy(dest, base_path);
95 strlcpy(dest + base_pathlen, uri, pathlen + 1);
98 return dest + base_pathlen;
102 static esp_err_t index_html_get_handler(httpd_req_t *req)
104 httpd_resp_set_status(req,
"307 Temporary Redirect");
105 httpd_resp_set_hdr(req,
"Location",
"/");
106 httpd_resp_send(req, NULL, 0);
124 static esp_err_t font_regular_get_handler(httpd_req_t *req)
126 extern const unsigned char font_regular_start[]
asm(
"_binary_overpass_regular_otf_start");
127 extern const unsigned char font_regular_end[]
asm(
"_binary_overpass_regular_otf_end");
128 const size_t font_regular_size = (font_regular_end - font_regular_start);
129 httpd_resp_set_type(req,
"font/otf");
130 httpd_resp_send(req, (
const char *)font_regular_start, font_regular_size);
133 static esp_err_t font_get_handler(httpd_req_t *req)
135 extern const unsigned char font_start[]
asm(
"_binary_overpass_otf_start");
136 extern const unsigned char font_end[]
asm(
"_binary_overpass_otf_end");
137 const size_t font_size = (font_end - font_start);
138 httpd_resp_set_type(req,
"font/otf");
139 httpd_resp_send(req, (
const char *)font_start, font_size);
144 static esp_err_t set_content_type_from_file(httpd_req_t *req,
const char *filename)
148 return httpd_resp_set_type(req,
"application/pdf");
152 return httpd_resp_set_type(req,
"text/html");
156 return httpd_resp_set_type(req,
"image/jpeg");
160 return httpd_resp_set_type(req,
"image/x-icon");
164 return httpd_resp_set_type(req,
"text/plain");
170 if (stat(filename, &st) == 0)
172 ESP_LOGI(
TAG,
"file size: %ld", st.st_size);
175 ESP_LOGI(
TAG,
"Cannot determine size of %s\n",
180 static esp_err_t http_resp_index_html(httpd_req_t *req,
const char *dirpath)
182 extern const unsigned char index_start[]
asm(
"_binary_index_html_start");
183 extern const unsigned char index_end[]
asm(
"_binary_index_html_end");
184 const size_t index_size = (index_end - index_start);
185 httpd_resp_send_chunk(req, (
const char *)index_start, index_size);
186 httpd_resp_sendstr_chunk(req, NULL);
189 static esp_err_t http_resp_robots_txt(httpd_req_t *req,
const char *dirpath)
191 extern const unsigned char robots_start[]
asm(
"_binary_robots_txt_start");
192 extern const unsigned char robots_end[]
asm(
"_binary_robots_txt_end");
193 const size_t robots_size = (robots_end - robots_start);
194 httpd_resp_send_chunk(req, (
const char *)robots_start, robots_size);
195 httpd_resp_sendstr_chunk(req, NULL);
198 static esp_err_t http_resp_bundle_js(httpd_req_t *req,
const char *dirpath)
200 extern const unsigned char bundle_start[]
asm(
"_binary_bundle_js_start");
201 extern const unsigned char bundle_end[]
asm(
"_binary_bundle_js_end");
202 const size_t bundle_size = (bundle_end - bundle_start);
203 httpd_resp_set_type(req,
"text/javascript");
204 httpd_resp_send_chunk(req, (
const char *)bundle_start, bundle_size);
205 httpd_resp_sendstr_chunk(req, NULL);
208 static esp_err_t http_resp_bundle_js_map(httpd_req_t *req,
const char *dirpath)
210 extern const unsigned char bundle_js_map_start[]
asm(
"_binary_bundle_js_map_start");
211 extern const unsigned char bundle_js_map_end[]
asm(
"_binary_bundle_js_map_end");
212 const size_t bundle_js_map_size = (bundle_js_map_end - bundle_js_map_start);
213 httpd_resp_set_type(req,
"text/javascript");
214 httpd_resp_send_chunk(req, (
const char *)bundle_js_map_start, bundle_js_map_size);
215 httpd_resp_sendstr_chunk(req, NULL);
218 static esp_err_t http_resp_bundle_css(httpd_req_t *req,
const char *dirpath)
220 extern const unsigned char bundle_css_start[]
asm(
"_binary_bundle_css_start");
221 extern const unsigned char bundle_css_end[]
asm(
"_binary_bundle_css_end");
222 const size_t bundle_css_size = (bundle_css_end - bundle_css_start);
223 httpd_resp_set_type(req,
"text/css");
224 httpd_resp_send_chunk(req, (
const char *)bundle_css_start, bundle_css_size);
225 httpd_resp_sendstr_chunk(req, NULL);
228 static esp_err_t http_resp_global_css(httpd_req_t *req,
const char *dirpath)
230 extern const unsigned char global_start[]
asm(
"_binary_global_css_start");
231 extern const unsigned char global_end[]
asm(
"_binary_global_css_end");
232 const size_t global_size = (global_end - global_start);
233 httpd_resp_set_type(req,
"text/css");
234 httpd_resp_send_chunk(req, (
const char *)global_start, global_size);
235 httpd_resp_sendstr_chunk(req, NULL);
239 static esp_err_t update_get_handler(httpd_req_t *req)
241 ESP_LOGD(
TAG,
"update received %s", req->uri);
242 httpd_resp_set_status(req,
"200 OK");
243 httpd_resp_set_type(req,
"text/html; charset=UTF-8");
246 httpd_resp_sendstr(req, line);
251 static esp_err_t download_get_handler(httpd_req_t *req)
253 ESP_LOGI(
TAG,
"download for %s", req->uri);
256 struct stat file_stat;
258 const char *filename = get_path_from_uri(filepath, ((
struct file_server_data *)req->user_ctx)->base_path,
259 req->uri,
sizeof(filepath));
262 ESP_LOGE(
TAG,
"Filename is too long");
264 httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR,
"Filename too long");
269 if (filename[strlen(filename) - 1] ==
'/')
271 return http_resp_index_html(req, filepath);
274 if (stat(filepath, &file_stat) == -1)
278 if (strcmp(filename,
"/index.html") == 0)
280 return index_html_get_handler(req);
282 if (strcmp(filename,
"/overpass.otf") == 0)
284 return font_get_handler(req);
286 if (strcmp(filename,
"/overpass-regular.otf") == 0)
288 return font_regular_get_handler(req);
291 if (strcmp(filename,
"/bundle.js") == 0)
293 return http_resp_bundle_js(req, filepath);
295 if (strcmp(filename,
"/bundle.js.map") == 0)
297 return http_resp_bundle_js_map(req, filepath);
300 if (strcmp(filename,
"/bundle.css") == 0)
302 return http_resp_bundle_css(req, filepath);
305 if (strcmp(filename,
"/global.css") == 0)
307 return http_resp_global_css(req, filepath);
310 if (strcmp(filename,
"/robots.txt") == 0)
312 return http_resp_robots_txt(req, filepath);
314 ESP_LOGE(
TAG,
"Failed to stat file : %s", filepath);
316 httpd_resp_send_err(req, HTTPD_404_NOT_FOUND,
"File does not exist");
320 fd = fopen(filepath,
"r");
323 ESP_LOGE(
TAG,
"Failed to read existing file : %s", filepath);
325 httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR,
"Failed to read existing file");
329 ESP_LOGI(
TAG,
"Sending file : %s (%ld bytes)...", filename, file_stat.st_size);
330 set_content_type_from_file(req, filename);
343 if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK)
346 ESP_LOGE(
TAG,
"File sending failed!");
348 httpd_resp_sendstr_chunk(req, NULL);
350 httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR,
"Failed to send file");
356 }
while (chunksize != 0);
360 ESP_LOGI(
TAG,
"File sending complete");
363 httpd_resp_send_chunk(req, NULL, 0);
367 static esp_err_t api_post_handler(httpd_req_t *req)
369 ESP_LOGI(
TAG,
"post received at %s with size %d", req->uri, req->content_len);
371 size_t recv_size = MIN(req->content_len,
sizeof(content));
372 int ret = httpd_req_recv(req, content, recv_size);
376 if (ret == HTTPD_SOCK_ERR_TIMEOUT)
381 httpd_resp_send_408(req);
388 ESP_LOGI(
TAG,
"post received with content: %s", content);
390 if (strcmp(req->uri,
"/api/set_temp") == 0)
392 goal = atof(content);
393 ESP_LOGI(
TAG,
"new goal as float: %0.2f", atof(content));
396 else if (strcmp(req->uri,
"/api/set_upper_margin") == 0)
398 over = atof(content);
399 ESP_LOGI(
TAG,
"new over as float: %0.2f", atof(content));
402 else if (strcmp(req->uri,
"/api/set_lower_margin") == 0)
404 under = atof(content);
405 ESP_LOGI(
TAG,
"new under as float: %0.2f", atof(content));
410 ESP_LOGI(
TAG,
"post call to %s not handled by implemented checks, respond unsupported", req->uri);
411 httpd_resp_set_status(req,
"501 Not Implemented");
412 httpd_resp_sendstr(req,
"couldn't match that req to a server function");
419 httpd_resp_set_status(req,
"303 See Other");
420 httpd_resp_set_hdr(req,
"Location",
"/");
421 httpd_resp_sendstr(req,
"post processed successfully");
436 ESP_LOGE(
TAG,
"File server presently supports only '/spiffs' as base path");
437 return ESP_ERR_INVALID_ARG;
442 ESP_LOGE(
TAG,
"File server already started");
443 return ESP_ERR_INVALID_STATE;
450 ESP_LOGE(
TAG,
"Failed to allocate memory for server data");
451 return ESP_ERR_NO_MEM;
456 httpd_handle_t server = NULL;
457 httpd_config_t config = HTTPD_DEFAULT_CONFIG();
462 config.uri_match_fn = httpd_uri_match_wildcard;
464 ESP_LOGI(
TAG,
"Starting HTTP Server");
465 if (httpd_start(&server, &config) != ESP_OK)
467 ESP_LOGE(
TAG,
"Failed to start file server!");
472 httpd_uri_t update = {
475 .handler = update_get_handler,
476 .user_ctx = server_data
478 httpd_register_uri_handler(server, &update);
481 httpd_uri_t file_download = {
484 .handler = download_get_handler,
485 .user_ctx = server_data
487 httpd_register_uri_handler(server, &file_download);
490 httpd_uri_t api_post = {
493 .handler = api_post_handler,
494 .user_ctx = server_data
496 httpd_register_uri_handler(server, &api_post);
char base_path[ESP_VFS_PATH_MAX+1]
char scratch[SCRATCH_BUFSIZE]
esp_err_t start_file_server(const char *base_path)
off_t ws_get_file_size(const char *filename)
defininitions for webserver
volatile float temp
current temp
#define IS_FILE_EXT(filename, ext)
volatile float under
margin below goal temp at which to turn relay on
volatile float goal
goal temp for the system to aim for
volatile float over
margin above goal temp at which to turn relay off
void update_display(void)