-
Notifications
You must be signed in to change notification settings - Fork 192
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Runs an HTTP server that will draw images on the screen. Useful for setting up a small digital frame that can be remotely controlled.
- Loading branch information
1 parent
2591847
commit 14c9ccb
Showing
14 changed files
with
4,846 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
cmake_minimum_required(VERSION 3.5) | ||
|
||
set(EXTRA_COMPONENT_DIRS "../../") | ||
|
||
include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||
project(http-server) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# HTTP server | ||
|
||
Runs an HTTP server that will draw images on the screen. | ||
Useful for setting up a small digital frame that can be remotely controlled. | ||
|
||
## Config | ||
1. In `main/server.h`, edit `WIFI_SSID` and `WIFI_PASSWORD` to match your wifi config | ||
2. In `main/main.c`, edit `n_epd_setup` to refer to the right EPD screen | ||
|
||
## Running | ||
flash (`idf.py flash`), then connect the EPDiy to a power source (computer is fine). | ||
The endpoints are: | ||
1. `GET /`, prints the screen temp / height / width as headers | ||
2. `POST /clear`, clears the screen | ||
3. `POST /draw`, expects: | ||
1. a body that is a binary stream already encoded to EPDiy's standards (like the one in `dragon.h`). | ||
2. Headers `width`, `height` | ||
3. Optional headers `x`,`y` (default to 0) | ||
4. Optional header `clear`, if set to nonzero integer will force-clear the screen before drawing | ||
|
||
## Helper script | ||
`send_image.py` is a friendlier client. | ||
```bash | ||
$ ./send_image.py ESP_IP info | ||
EpdInfo(width=1024, height=768, temperature=20) | ||
|
||
$ ./send_image.py ESP_IP clear | ||
# Clears the screen | ||
|
||
$ ./send_image.y ESP_IP draw /tmp/spooder-man.png | ||
# Draws on screen | ||
``` | ||
Thanks to argparse, all arguments are visible with `--help`. | ||
Requires `requests` and `PIL` (or Pillow) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# | ||
# "main" pseudo-component makefile. | ||
# | ||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
set( | ||
app_sources "epd.c" "server.c" "main.c" | ||
) | ||
|
||
idf_component_register( | ||
SRCS ${app_sources} | ||
REQUIRES epdiy esp_wifi nvs_flash esp_http_server esp_netif | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#include "epd.h" | ||
|
||
static EpdiyHighlevelState hl; | ||
static EpdData data; | ||
|
||
static inline void checkError(enum EpdDrawError err) { | ||
if (err != EPD_DRAW_SUCCESS) { | ||
ESP_LOGE("demo", "draw error: %X", err); | ||
} | ||
} | ||
|
||
EpdData n_epd_data() { | ||
return data; | ||
} | ||
|
||
void n_epd_setup(const EpdDisplay_t* display) { | ||
epd_init(&epd_board_v7, display, EPD_LUT_64K); | ||
epd_set_vcom(1560); | ||
hl = epd_hl_init(EPD_BUILTIN_WAVEFORM); | ||
epd_set_rotation(EPD_ROT_LANDSCAPE); | ||
data.width = epd_rotated_display_width(); | ||
data.height = epd_rotated_display_height(); | ||
data.temperature = epd_ambient_temperature(); | ||
} | ||
|
||
void n_epd_clear() { | ||
epd_poweron(); | ||
epd_fullclear(&hl, data.temperature); | ||
epd_poweroff(); | ||
} | ||
|
||
void n_epd_draw(uint8_t* content, int x, int y, int width, int height) { | ||
uint8_t* fb = epd_hl_get_framebuffer(&hl); | ||
EpdRect area = { | ||
.x = x, | ||
.y = y, | ||
.width = width, | ||
.height = height, | ||
}; | ||
epd_draw_rotated_image(area, content, fb); | ||
epd_poweron(); | ||
checkError(epd_hl_update_screen(&hl, MODE_GC16, data.temperature)); | ||
epd_poweroff(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#ifndef EPD_H | ||
#define EPD_H | ||
|
||
#include "epdiy.h" | ||
#include <esp_log.h> | ||
|
||
typedef struct { | ||
int width; | ||
int height; | ||
int temperature; | ||
} EpdData; | ||
|
||
EpdData n_epd_data(); | ||
void n_epd_setup(); | ||
void n_epd_clear(); | ||
void n_epd_draw(uint8_t* content, int x, int y, int width, int height); | ||
#endif /* EPD_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#include "server.h" | ||
#include "esp_http_server.h" | ||
#include "epd.h" | ||
#include "esp_heap_caps.h" | ||
#include "settings.h" | ||
|
||
#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) { | ||
EpdData data = n_epd_data(); | ||
char width[20], height[20], temperature[20]; | ||
WRITE_HEADER(req, width, "width", "%d", data.width); | ||
WRITE_HEADER(req, height, "height", "%d", data.height); | ||
WRITE_HEADER(req, temperature, "temperature", "%d", data.temperature); | ||
const char* response = "Hello! Check headers\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_clear(httpd_req_t* req) { | ||
ESP_LOGI(__FUNCTION__, "Clear\n"); | ||
n_epd_clear(); | ||
const char* response = "Cleared\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) { | ||
// optional headers: x,y. Default to 0 | ||
// required headers: height, width | ||
// Content should be a stream of special bytes - we're reading 4 bits at a time. | ||
int x, y, width, height, clear; | ||
char header[20]; | ||
memset(header, 0, 20); | ||
if (httpd_req_get_hdr_value_str(req, "clear", header, 20) == ESP_OK) { | ||
sscanf(header, "%d", &clear); | ||
} else { | ||
clear = 0; | ||
} | ||
if (httpd_req_get_hdr_value_str(req, "x", header, 20) == ESP_OK) { | ||
sscanf(header, "%d", &x); | ||
} else { | ||
x = 0; | ||
} | ||
if (httpd_req_get_hdr_value_str(req, "y", header, 20) == ESP_OK) { | ||
sscanf(header, "%d", &y); | ||
} else { | ||
y = 0; | ||
} | ||
if (httpd_req_get_hdr_value_str(req, "width", header, 20) == ESP_OK) { | ||
sscanf(header, "%d", &width); | ||
} else { | ||
char response[60]; | ||
sprintf(response, "Missing header width"); | ||
httpd_resp_set_type(req, "text/plain"); | ||
httpd_resp_set_status(req, "400"); | ||
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN); | ||
return ESP_OK; | ||
} | ||
if (httpd_req_get_hdr_value_str(req, "height", header, 20) == ESP_OK) { | ||
sscanf(header, "%d", &height); | ||
} else { | ||
char response[60]; | ||
sprintf(response, "Missing header height"); | ||
httpd_resp_set_type(req, "text/plain"); | ||
httpd_resp_set_status(req, "400"); | ||
httpd_resp_send(req, response, HTTPD_RESP_USE_STRLEN); | ||
return ESP_OK; | ||
} | ||
|
||
// 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 byets. 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); | ||
|
||
if (clear) { | ||
n_epd_clear(); | ||
} | ||
n_epd_draw(((uint8_t*)content), x, y, width, height); | ||
heap_caps_free(content); | ||
|
||
// Done reading | ||
char response[100]; | ||
sprintf( | ||
response, "x %d, y %d, width %d, height %d, byte count %d\n", x, y, width, height, req_size | ||
); | ||
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_paths(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 = "/clear", .method = HTTP_POST, .handler = http_clear, .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); | ||
} | ||
} | ||
|
||
void app_main(void) { | ||
// 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); | ||
|
||
httpd_handle_t server = get_server(); | ||
if (server != NULL) { | ||
register_paths(server); | ||
} | ||
n_epd_setup(&SCREEN_MODEL); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
#include "server.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 = { | ||
.sta = { | ||
.ssid = WIFI_SSID, | ||
.password = WIFI_PASSWORD, | ||
}, | ||
}; | ||
|
||
// 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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#ifndef SETTINGS_H | ||
#define SETTINGS_H | ||
|
||
#define WIFI_SSID "best ssid" // Replace with your Wi-Fi SSID | ||
#define WIFI_PASSWORD "great password much wow" // Replace with your Wi-Fi password | ||
|
||
#define SCREEN_MODEL ED060XC3 | ||
|
||
#endif /* SETTINGS_H */ |
Oops, something went wrong.