trying to make correct multipart POST request
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build
|
||||
*.old
|
||||
|
||||
13
CMakeLists.txt
Normal file
13
CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
$ENV{IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
components/esp32-camera
|
||||
)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp32_timelapse_camera)
|
||||
11
Makefile
Normal file
11
Makefile
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := esp32_timelapse_camera
|
||||
|
||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
4
main/CMakeLists.txt
Normal file
4
main/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS "."
|
||||
EMBED_TXTFILES "certs/cacert.pem"
|
||||
"certs/prvtkey.pem")
|
||||
5
main/component.mk
Normal file
5
main/component.mk
Normal file
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
239
main/main.c
Normal file
239
main/main.c
Normal file
@@ -0,0 +1,239 @@
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_system.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_tls.h"
|
||||
|
||||
#include "esp_camera.h"
|
||||
#include "img_converters.h"
|
||||
#include "esp_timer.h"
|
||||
#include "protocol_examples_common.h"
|
||||
|
||||
#define MAX_HTTP_RECV_BUFFER 512
|
||||
|
||||
#define PWDN_GPIO_NUM 32
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 0
|
||||
#define SIOD_GPIO_NUM 26
|
||||
#define SIOC_GPIO_NUM 27
|
||||
#define Y9_GPIO_NUM 35
|
||||
#define Y8_GPIO_NUM 34
|
||||
#define Y7_GPIO_NUM 39
|
||||
#define Y6_GPIO_NUM 36
|
||||
#define Y5_GPIO_NUM 21
|
||||
#define Y4_GPIO_NUM 19
|
||||
#define Y3_GPIO_NUM 18
|
||||
#define Y2_GPIO_NUM 5
|
||||
#define VSYNC_GPIO_NUM 25
|
||||
#define HREF_GPIO_NUM 23
|
||||
#define PCLK_GPIO_NUM 22
|
||||
#define INTERVAL 5 * 1000 // millisecond
|
||||
|
||||
#define PART_BOUNDARY "123456789000000000000987654321"
|
||||
|
||||
static const char *TAG = "timelapse";
|
||||
|
||||
esp_err_t _http_event_handler(esp_http_client_event_t *evt);
|
||||
static void post_data(camera_fb_t * photo);
|
||||
|
||||
static camera_config_t cam_config = {
|
||||
.ledc_channel = LEDC_CHANNEL_0,
|
||||
.ledc_timer = LEDC_TIMER_0,
|
||||
.pin_d0 = Y2_GPIO_NUM,
|
||||
.pin_d1 = Y3_GPIO_NUM,
|
||||
.pin_d2 = Y4_GPIO_NUM,
|
||||
.pin_d3 = Y5_GPIO_NUM,
|
||||
.pin_d4 = Y6_GPIO_NUM,
|
||||
.pin_d5 = Y7_GPIO_NUM,
|
||||
.pin_d6 = Y8_GPIO_NUM,
|
||||
.pin_d7 = Y9_GPIO_NUM,
|
||||
.pin_xclk = XCLK_GPIO_NUM,
|
||||
.pin_pclk = PCLK_GPIO_NUM,
|
||||
.pin_vsync = VSYNC_GPIO_NUM,
|
||||
.pin_href = HREF_GPIO_NUM,
|
||||
.pin_sscb_sda = SIOD_GPIO_NUM,
|
||||
.pin_sscb_scl = SIOC_GPIO_NUM,
|
||||
.pin_pwdn = PWDN_GPIO_NUM,
|
||||
.pin_reset = RESET_GPIO_NUM,
|
||||
.xclk_freq_hz = 20000000,
|
||||
.pixel_format = PIXFORMAT_JPEG,
|
||||
|
||||
// need to enable psram in menuconfig
|
||||
.frame_size = FRAMESIZE_UXGA,
|
||||
.jpeg_quality = 10,
|
||||
.fb_count = 2
|
||||
};
|
||||
|
||||
static esp_err_t init_camera() {
|
||||
esp_err_t err = esp_camera_init(&cam_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Camera Init Failed, error 0x%x", err);
|
||||
return err;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// initialization
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
// connect to wifi
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
// OV2640 camera module
|
||||
if (init_camera() != ESP_OK) {
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
vTaskDelay( 1000 / portTICK_RATE_MS );
|
||||
camera_fb_t * pic = NULL; // pointer
|
||||
while (1) {
|
||||
ESP_LOGI(TAG, "taking a photo...");
|
||||
pic = esp_camera_fb_get();
|
||||
// use pic->buf to access the image
|
||||
ESP_LOGI(TAG, "Photo taken, size is %zu bytes", pic->len);
|
||||
ESP_LOGI(TAG, "sending the photo ...");
|
||||
post_data(pic);
|
||||
|
||||
esp_camera_fb_return(pic);
|
||||
vTaskDelay(INTERVAL / portTICK_RATE_MS);
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t CHUNK_SIZE = 1024;
|
||||
static const uint32_t MSG_SIZE = 256;
|
||||
static const char * uploadPath = "/upload";
|
||||
static const char * server = "192.168.1.107:3001";
|
||||
static const char * boundary = "01234567899876543210";
|
||||
|
||||
static void post_data(camera_fb_t * pic){
|
||||
char url[128];
|
||||
sprintf(url, "http://%s%s", server, uploadPath);
|
||||
esp_http_client_config_t config = { .url = url,
|
||||
.event_handler = _http_event_handler};
|
||||
esp_http_client_handle_t client = esp_http_client_init(&config);
|
||||
esp_http_client_set_method(client, HTTP_METHOD_POST);
|
||||
|
||||
char header[CHUNK_SIZE];
|
||||
char head[MSG_SIZE];
|
||||
char tail[MSG_SIZE];
|
||||
|
||||
sprintf(head, "--%s\r\n"
|
||||
"Content-Disposition: form-data; name=\"photo\"; filename=\"esp32.jpg\"\r\n"
|
||||
"Content-Type: image/jpeg\r\n\r\n", boundary);
|
||||
sprintf(tail, "\r\n--%s--\r\n", boundary);
|
||||
size_t totalLen = pic->len + strlen(head) + strlen(tail);
|
||||
|
||||
char tmpStr[MSG_SIZE];
|
||||
|
||||
// send header so that the server knows what to do with chunks after this
|
||||
sprintf(header, "POST %s HTTP/1.1\r\nHost: %s\r\n"
|
||||
"Content-Length: %u\r\n"
|
||||
"Expect: 100-continue\r\n"
|
||||
"Accept: */*\r\n"
|
||||
"Content-Type: multipart/form-data; boundary=%s\r\n\r\n"
|
||||
, uploadPath, server, pic->len, boundary);
|
||||
ESP_LOGI(TAG, "header to be sent:\n%s", header);
|
||||
|
||||
esp_http_client_open(client, totalLen);
|
||||
|
||||
// send the first header
|
||||
esp_http_client_write(client, header, strlen(header));
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
esp_http_client_fetch_headers(client);
|
||||
ESP_LOGI(TAG, "code %d", esp_http_client_get_status_code(client));
|
||||
|
||||
/* char resp[CHUNK_SIZE]; */
|
||||
/* esp_http_client_read(client, resp, CHUNK_SIZE); */
|
||||
/* ESP_LOGI(TAG, "%s", resp); */
|
||||
|
||||
// send head
|
||||
esp_http_client_write(client, head, strlen(head));
|
||||
ESP_LOGI(TAG, "%s", (char *)head);
|
||||
|
||||
size_t nChunks = pic->len / CHUNK_SIZE + 1;
|
||||
|
||||
uint8_t *ptr = pic->buf;
|
||||
size_t fbLen = pic->len;
|
||||
ESP_LOGI(TAG, "photo size 0x%x, will be posted in %u chunks", fbLen, nChunks);
|
||||
|
||||
for (size_t n = 0; n < fbLen; n += CHUNK_SIZE) {
|
||||
if (n + CHUNK_SIZE < fbLen) {
|
||||
esp_http_client_write(client, (char *)ptr, CHUNK_SIZE);
|
||||
if (n<2) {
|
||||
sprintf(tmpStr, "%u:", n);
|
||||
for (int i = 0; i < 15; i++) {
|
||||
char nextChar[4];
|
||||
sprintf(nextChar, "%x", ptr[i]);
|
||||
strcat(tmpStr, nextChar);
|
||||
}
|
||||
ESP_LOGI(TAG, "%.16s", tmpStr);
|
||||
}
|
||||
ptr += CHUNK_SIZE;
|
||||
}
|
||||
else if (fbLen % CHUNK_SIZE > 0){
|
||||
esp_http_client_write(client, (char *)ptr, fbLen % CHUNK_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s", (char *)tail);
|
||||
esp_http_client_write(client, tail, strlen(tail));
|
||||
esp_http_client_fetch_headers(client);
|
||||
ESP_LOGI(TAG, "response %d", esp_http_client_get_status_code(client));
|
||||
|
||||
esp_http_client_cleanup(client);
|
||||
}
|
||||
|
||||
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
|
||||
{
|
||||
switch(evt->event_id) {
|
||||
case HTTP_EVENT_ERROR:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
|
||||
break;
|
||||
case HTTP_EVENT_ON_CONNECTED:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
|
||||
break;
|
||||
case HTTP_EVENT_HEADER_SENT:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
|
||||
break;
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
|
||||
break;
|
||||
case HTTP_EVENT_ON_DATA:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
|
||||
if (!esp_http_client_is_chunked_response(evt->client)) {
|
||||
// Write out data
|
||||
// printf("%.*s", evt->data_len, (char*)evt->data);
|
||||
}
|
||||
|
||||
break;
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
|
||||
break;
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
|
||||
int mbedtls_err = 0;
|
||||
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
|
||||
if (err != 0) {
|
||||
ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
|
||||
ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user