Add HTTP server
This commit is contained in:
parent
6b2d89340a
commit
8bd9a9b1d0
7 changed files with 206 additions and 8 deletions
13
README.md
13
README.md
|
|
@ -2,6 +2,19 @@
|
||||||
|
|
||||||
This repository contains the sources required to run the Inkpot frontend on a Lilygo T5, an ESP32 equipped with an e-ink display. It allows you to create Lua sketches that draw on the e-ink screen.
|
This repository contains the sources required to run the Inkpot frontend on a Lilygo T5, an ESP32 equipped with an e-ink display. It allows you to create Lua sketches that draw on the e-ink screen.
|
||||||
|
|
||||||
|
You need to give it a 2.4Ghz Wifi SSID and password by adjusting `main/settings.h`. After that it will start an HTTP server that you can use to interact with the device. The HTTP server has two endpoints:
|
||||||
|
|
||||||
|
- `GET /` -- Hello world page to confirm that things are working
|
||||||
|
- `POST /draw` -- Accepts a Lua POST body and will execute the script
|
||||||
|
|
||||||
|
You can send scripts like this:
|
||||||
|
|
||||||
|
``` bash
|
||||||
|
cat foo.lua | curl -X POST --data-binary @- 10.0.0.100/draw
|
||||||
|
```
|
||||||
|
|
||||||
|
The IP address of the display is logged to its serial output and can be read via `idf.py monitor` (see below).
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
There is a `flake.nix` at the root of this repository that defines a development environment with all required tools. If you are using `direnv`, `cd` into the repositorie's root directory after cloning it and run `direnv allow`. If you aren't using direnv the enviroment can be activated using `nix develop .`.
|
There is a `flake.nix` at the root of this repository that defines a development environment with all required tools. If you are using `direnv`, `cd` into the repositorie's root directory after cloning it and run `direnv allow`. If you aren't using direnv the enviroment can be activated using `nix develop .`.
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,43 @@ print(
|
||||||
'height: ' .. height
|
'height: ' .. height
|
||||||
)
|
)
|
||||||
|
|
||||||
for i = 1, 50 do
|
-- easing functions taken from https://easings.net/
|
||||||
x = math.random() * width
|
|
||||||
y = math.random() * height
|
|
||||||
r = 24 + math.ceil(math.random() * 12)
|
|
||||||
|
|
||||||
paper.fill_circle(x, y, r, math.floor(math.random() * 0xFF))
|
function ease_in_sine(x)
|
||||||
|
return 1 - math.cos(x * math.pi / 2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ease_in_out_sine(x)
|
||||||
|
return -(math.cos(math.pi * x) - 1) / 2
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- actual sketch follows below
|
||||||
|
--
|
||||||
|
|
||||||
|
local x = width / 2
|
||||||
|
local max_radius = 128
|
||||||
|
local min_radius = max_radius / 6
|
||||||
|
local padding = max_radius
|
||||||
|
local max_color = 0xDD
|
||||||
|
local min_color = 0x33
|
||||||
|
local steps = 72
|
||||||
|
|
||||||
|
-- background
|
||||||
|
paper.fill_rect(0, 0, width, height, 0x22)
|
||||||
|
|
||||||
|
-- sketch
|
||||||
|
for i = 1, steps do
|
||||||
|
local n = i / steps
|
||||||
|
local e1 = ease_in_sine(n)
|
||||||
|
local e2 = 1 - ease_in_out_sine(ease_in_sine(n))
|
||||||
|
local color = math.floor(max_color - (max_color - min_color) * e2)
|
||||||
|
paper.fill_circle(
|
||||||
|
x + math.sin((math.pi * 2) / n) * 32 * e1,
|
||||||
|
padding + (height - max_radius - padding * 2) * e1,
|
||||||
|
min_radius + (max_radius - min_radius) * e1,
|
||||||
|
color
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
paper.update()
|
paper.update()
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,6 @@ idf_component_register(
|
||||||
SRCS
|
SRCS
|
||||||
"inkpot.c"
|
"inkpot.c"
|
||||||
"paper.c"
|
"paper.c"
|
||||||
|
"server.c"
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "."
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
#include "paper.h"
|
#include "paper.h"
|
||||||
|
#include "server.h"
|
||||||
|
|
||||||
#define WIFI_SCAN_LIST_SIZE 10
|
#define WIFI_SCAN_LIST_SIZE 10
|
||||||
#define LUA_FILE_PATH "/assets"
|
#define LUA_FILE_PATH "/assets"
|
||||||
|
|
@ -96,7 +97,7 @@ void run_lua_file(const char *file_name, const char *test_name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to run an embedded Lua script
|
// Function to run an embedded Lua script
|
||||||
void run_embedded_lua_test(const char *lua_script, const char *test_name) {
|
void run_lua_string(const char *lua_script, const char *test_name) {
|
||||||
ESP_LOGI(TAG, "Starting Lua test: %s", test_name);
|
ESP_LOGI(TAG, "Starting Lua test: %s", test_name);
|
||||||
|
|
||||||
log_memory_usage("Start of test");
|
log_memory_usage("Start of test");
|
||||||
|
|
@ -176,19 +177,96 @@ void scan_wifi_networks(void) {
|
||||||
ESP_LOGI(TAG, "Wi-Fi scan completed.");
|
ESP_LOGI(TAG, "Wi-Fi scan completed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void app_main(void) {
|
// HTTP Server
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define WRITE_HEADER(req, buffer, name, format, src) \
|
||||||
|
sprintf(buffer, format, src); \
|
||||||
|
ESP_ERROR_CHECK(httpd_resp_set_hdr(req, name, buffer));
|
||||||
|
|
||||||
|
static esp_err_t http_index(httpd_req_t* req) {
|
||||||
|
// TODO: Serve HTML file with form POSTing to `/draw`
|
||||||
|
const char* response = "Hello world!\n";
|
||||||
|
httpd_resp_set_type(req, "text/plain");
|
||||||
|
httpd_resp_set_status(req, "200");
|
||||||
|
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t http_draw(httpd_req_t* req) {
|
||||||
|
// READING STREAM
|
||||||
|
int req_size = req->content_len;
|
||||||
|
char* content = (char*)heap_caps_malloc(req_size, MALLOC_CAP_SPIRAM);
|
||||||
|
if (content == NULL) {
|
||||||
|
char msg[50];
|
||||||
|
sprintf(msg, "Failed to allocate %d chars\n", req_size);
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, msg);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
int current_pos = 0;
|
||||||
|
int amount_recieved;
|
||||||
|
while ((amount_recieved = httpd_req_recv(req, (content + current_pos), req_size)) > 0) {
|
||||||
|
ESP_LOGI(__FUNCTION__, "Read %d bytes\n", amount_recieved);
|
||||||
|
current_pos += amount_recieved;
|
||||||
|
}
|
||||||
|
if (amount_recieved < 0) {
|
||||||
|
char msg[50];
|
||||||
|
heap_caps_free(content);
|
||||||
|
ESP_LOGE(msg, "Failed to read bytes. Error code %d\n", amount_recieved);
|
||||||
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, msg);
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
ESP_LOGI(__FUNCTION__, "Done reading %d bytes out of %d\n", current_pos, req_size);
|
||||||
|
|
||||||
|
// TODO: Error handling
|
||||||
|
run_lua_string(content, "E-Paper Script via HTTP");
|
||||||
|
heap_caps_free(content);
|
||||||
|
|
||||||
|
// Done reading
|
||||||
|
char response[100];
|
||||||
|
sprintf(
|
||||||
|
response, "script drawn!"
|
||||||
|
);
|
||||||
|
httpd_resp_set_type(req, "text/plain");
|
||||||
|
httpd_resp_set_status(req, "200");
|
||||||
|
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_http_routes(httpd_handle_t server) {
|
||||||
|
{
|
||||||
|
httpd_uri_t uri
|
||||||
|
= { .uri = "/", .method = HTTP_GET, .handler = http_index, .user_ctx = NULL };
|
||||||
|
httpd_register_uri_handler(server, &uri);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
httpd_uri_t uri
|
||||||
|
= { .uri = "/draw", .method = HTTP_POST, .handler = http_draw, .user_ctx = NULL };
|
||||||
|
httpd_register_uri_handler(server, &uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
|
||||||
|
void app_main(void) {
|
||||||
// Initialize and mount the filesystem
|
// Initialize and mount the filesystem
|
||||||
init_filesystem();
|
init_filesystem();
|
||||||
|
|
||||||
|
// Initialize NVS, needed for wifi
|
||||||
|
esp_err_t ret = nvs_flash_init();
|
||||||
|
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
|
ret = nvs_flash_init();
|
||||||
|
}
|
||||||
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
|
// Set up HTTP server
|
||||||
|
httpd_handle_t server = get_server();
|
||||||
|
if (server != NULL) {
|
||||||
|
register_http_routes(server);
|
||||||
|
}
|
||||||
|
|
||||||
// Run script in assets/epaper.lua
|
// Run script in assets/epaper.lua
|
||||||
run_lua_file("epaper.lua", "E-Paper Script");
|
run_lua_file("epaper.lua", "E-Paper Startup Script");
|
||||||
|
|
||||||
ESP_LOGI(TAG, "End of testing application.");
|
ESP_LOGI(TAG, "End of testing application.");
|
||||||
|
|
||||||
|
|
|
||||||
49
main/server.c
Normal file
49
main/server.c
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#include "server.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
httpd_handle_t get_server(void);
|
||||||
|
|
||||||
|
static void wifi_init_sta(void) {
|
||||||
|
// Initialize the ESP-NETIF
|
||||||
|
esp_netif_init();
|
||||||
|
esp_event_loop_create_default();
|
||||||
|
|
||||||
|
// Create default event loop
|
||||||
|
esp_netif_create_default_wifi_sta();
|
||||||
|
|
||||||
|
// Initialize the Wi-Fi driver
|
||||||
|
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||||
|
|
||||||
|
// Set Wi-Fi mode to station
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||||
|
|
||||||
|
// Configure Wi-Fi connection
|
||||||
|
wifi_config_t wifi_config = {
|
||||||
|
// TODO: Allow setting SSID at boot or build time
|
||||||
|
// For some reason I could not get https://cmake.org/cmake/help/latest/command/add_compile_definitions.html#command:add_compile_definitions to work
|
||||||
|
.sta = {
|
||||||
|
.ssid = WIFI_SSID,
|
||||||
|
.password = WIFI_PASS,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set the Wi-Fi configuration
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
|
ESP_ERROR_CHECK(esp_wifi_connect());
|
||||||
|
}
|
||||||
|
|
||||||
|
httpd_handle_t start_webserver(void) {
|
||||||
|
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||||
|
config.lru_purge_enable = true;
|
||||||
|
|
||||||
|
httpd_handle_t server = NULL;
|
||||||
|
ESP_ERROR_CHECK(httpd_start(&server, &config));
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpd_handle_t get_server(void) {
|
||||||
|
wifi_init_sta();
|
||||||
|
return start_webserver();
|
||||||
|
}
|
||||||
19
main/server.h
Normal file
19
main/server.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef SERVER_H_
|
||||||
|
#define SERVER_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include "esp_event.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "esp_wifi.h"
|
||||||
|
#include "esp_netif.h"
|
||||||
|
#include "esp_http_server.h"
|
||||||
|
|
||||||
|
// #include "settings.h"
|
||||||
|
|
||||||
|
httpd_handle_t get_server(void);
|
||||||
|
|
||||||
|
#endif // SERVER_H_
|
||||||
7
main/settings.h
Normal file
7
main/settings.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef SETTINGS_H_
|
||||||
|
#define SETTINGS_H_
|
||||||
|
|
||||||
|
#define WIFI_SSID ""
|
||||||
|
#define WIFI_PASS ""
|
||||||
|
|
||||||
|
#endif // SETTINGS_H_
|
||||||
Loading…
Add table
Add a link
Reference in a new issue