All functioning...except OTA...
This commit is contained in:
parent
79c9c5b623
commit
5c5a04d55d
752
app_httpd.cpp
752
app_httpd.cpp
|
@ -1,45 +1,41 @@
|
|||
#include "esp_http_server.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_camera.h"
|
||||
#include "img_converters.h"
|
||||
#include "Arduino.h"
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClient.h>
|
||||
#include <esp_bt.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_sleep.h>
|
||||
#include <driver/rtc_io.h>
|
||||
#include "myconfig.h"
|
||||
#include "esp_camera.h"
|
||||
#include "camera_pins.h"
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <Update.h>
|
||||
|
||||
#include "index_ov2640.h"
|
||||
#include "index_ov3660.h"
|
||||
#include "index_other.h"
|
||||
#include "css.h"
|
||||
#include "src/html/firmware.h"
|
||||
#include "src/html/index_ov2640.h"
|
||||
#include "src/html/index_ov3660.h"
|
||||
#include "src/html/index_simple.h"
|
||||
#include "src/html/css.h"
|
||||
#include "src/favicons.h"
|
||||
#include "src/logo.h"
|
||||
#include "storage.h"
|
||||
|
||||
#if !defined(HTTP_PORT)
|
||||
#define HTTP_PORT 80
|
||||
#endif
|
||||
int httpPort = HTTP_PORT;
|
||||
|
||||
|
||||
// Functions from the main .ino
|
||||
extern void flashLED(int flashtime);
|
||||
extern void setLamp(int newVal);
|
||||
extern void resetWiFiConfig();
|
||||
|
||||
// External variables declared in the main .ino
|
||||
extern char myName[];
|
||||
extern char camera_name[];
|
||||
extern char myVer[];
|
||||
extern char baseVersion[];
|
||||
extern IPAddress ip;
|
||||
extern IPAddress net;
|
||||
extern IPAddress gw;
|
||||
extern bool accesspoint;
|
||||
extern char apName[];
|
||||
extern bool captivePortal;
|
||||
extern char httpURL[];
|
||||
extern IPAddress espIP;
|
||||
extern IPAddress espSubnet;
|
||||
extern IPAddress espGateway;
|
||||
extern char streamURL[];
|
||||
extern char default_index[];
|
||||
extern int myRotation;
|
||||
extern int lampVal;
|
||||
extern int8_t detection_enabled;
|
||||
extern int8_t recognition_enabled;
|
||||
extern bool filesystem;
|
||||
extern bool debugData;
|
||||
extern int sketchSize;
|
||||
|
@ -50,35 +46,37 @@ extern String sketchMD5;
|
|||
#include "fd_forward.h"
|
||||
#include "fr_forward.h"
|
||||
|
||||
#define ENROLL_CONFIRM_TIMES 5
|
||||
typedef struct
|
||||
{
|
||||
httpd_req_t *req;
|
||||
size_t len;
|
||||
} jpg_chunking_t;
|
||||
#if !defined(HTTP_PORT)
|
||||
#define HTTP_PORT 80
|
||||
#endif
|
||||
int httpPort = HTTP_PORT;
|
||||
char httpURL[64] = {"Undefined"};
|
||||
|
||||
AsyncWebServer appServer(httpPort);
|
||||
|
||||
bool updating;
|
||||
|
||||
void appServerCB(void *pvParameters);
|
||||
size_t jpg_encode_stream(void *arg, size_t index, const void *data, size_t len);
|
||||
void capture_handler(AsyncWebServerRequest *request);
|
||||
void cmd_handler(AsyncWebServerRequest *request);
|
||||
void status_handler(AsyncWebServerRequest *request);
|
||||
void favicon_16x16_handler(AsyncWebServerRequest *request);
|
||||
void favicon_32x32_handler(AsyncWebServerRequest *request);
|
||||
void favicon_ico_handler(AsyncWebServerRequest *request);
|
||||
void logo_svg_handler(AsyncWebServerRequest *request);
|
||||
void dump_handler(AsyncWebServerRequest *request);
|
||||
void style_handler(AsyncWebServerRequest *request);
|
||||
void handleIndex(AsyncWebServerRequest *request);
|
||||
void handleFirmware(AsyncWebServerRequest *request);
|
||||
void handleCameraClient();
|
||||
void startCameraServer();
|
||||
|
||||
#define PART_BOUNDARY "123456789000000000000987654321";
|
||||
httpd_handle_t camera_httpd = NULL;
|
||||
|
||||
static size_t jpg_encode_stream(void *arg, size_t index, const void *data, size_t len)
|
||||
{
|
||||
jpg_chunking_t *j = (jpg_chunking_t *)arg;
|
||||
if (!index)
|
||||
{
|
||||
j->len = 0;
|
||||
}
|
||||
if (httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
j->len += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
static esp_err_t capture_handler(httpd_req_t *req)
|
||||
void capture_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
camera_fb_t *fb = NULL;
|
||||
esp_err_t res = ESP_OK;
|
||||
|
||||
Serial.println("Capture Requested");
|
||||
|
||||
|
@ -90,208 +88,118 @@ static esp_err_t capture_handler(httpd_req_t *req)
|
|||
if (!fb)
|
||||
{
|
||||
Serial.println("Camera capture failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
request->send(500, "text/plain", "Camera Capture Failed");
|
||||
return;
|
||||
}
|
||||
|
||||
httpd_resp_set_type(req, "image/jpeg");
|
||||
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
size_t out_len, out_width, out_height;
|
||||
uint8_t *out_buf;
|
||||
bool s;
|
||||
if (!detection_enabled || fb->width > 400)
|
||||
{
|
||||
size_t fb_len = 0;
|
||||
if (fb->format == PIXFORMAT_JPEG)
|
||||
{
|
||||
fb_len = fb->len;
|
||||
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
|
||||
request->send(200, "image/jpeg", (const char *)fb->buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
jpg_chunking_t jchunk = {req, 0};
|
||||
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk) ? ESP_OK : ESP_FAIL;
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
fb_len = jchunk.len;
|
||||
request->send(500, "text/plain", "Camera Capture Failed");
|
||||
}
|
||||
esp_camera_fb_return(fb);
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
Serial.printf("JPG: %uB %ums\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000));
|
||||
return res;
|
||||
}
|
||||
|
||||
dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
|
||||
if (!image_matrix)
|
||||
{
|
||||
esp_camera_fb_return(fb);
|
||||
Serial.println("dl_matrix3du_alloc failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
out_buf = image_matrix->item;
|
||||
out_len = fb->width * fb->height * 3;
|
||||
out_width = fb->width;
|
||||
out_height = fb->height;
|
||||
|
||||
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
|
||||
esp_camera_fb_return(fb);
|
||||
if (!s)
|
||||
{
|
||||
dl_matrix3du_free(image_matrix);
|
||||
Serial.println("to rgb888 failed");
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
jpg_chunking_t jchunk = {req, 0};
|
||||
s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
|
||||
dl_matrix3du_free(image_matrix);
|
||||
if (!s)
|
||||
{
|
||||
Serial.println("JPEG compression failed");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
if (debugData)
|
||||
{
|
||||
Serial.printf("FACE: %uB %ums\n", (uint32_t)(jchunk.len), (uint32_t)((fr_end - fr_start) / 1000));
|
||||
}
|
||||
return res;
|
||||
Serial.printf("JPG: %uB %ums\r\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start) / 1000));
|
||||
}
|
||||
|
||||
static esp_err_t cmd_handler(httpd_req_t *req)
|
||||
void cmd_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
char *buf;
|
||||
size_t buf_len;
|
||||
char variable[32] = {
|
||||
0,
|
||||
};
|
||||
char value[32] = {
|
||||
0,
|
||||
};
|
||||
Serial.println("Command received!");
|
||||
flashLED(75);
|
||||
|
||||
buf_len = httpd_req_get_url_query_len(req) + 1;
|
||||
if (buf_len > 1)
|
||||
if (!request->hasArg("var") || !request->hasArg("val"))
|
||||
{
|
||||
buf = (char *)malloc(buf_len);
|
||||
if (!buf)
|
||||
{
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK)
|
||||
{
|
||||
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
|
||||
httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buf);
|
||||
httpd_resp_send_404(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buf);
|
||||
httpd_resp_send_404(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpd_resp_send_404(req);
|
||||
return ESP_FAIL;
|
||||
Serial.println("No var or val");
|
||||
request->send(404, "text/plain", "Invalid parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
int val = atoi(value);
|
||||
String variable = request->arg("var").c_str();
|
||||
String value = request->arg("val").c_str();
|
||||
|
||||
Serial.print("Var ");
|
||||
Serial.println(variable);
|
||||
|
||||
int val = atoi(value.c_str());
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
int res = 0;
|
||||
if (!strcmp(variable, "framesize"))
|
||||
if (variable.compareTo("framesize") == 0)
|
||||
{
|
||||
if (s->pixformat == PIXFORMAT_JPEG)
|
||||
res = s->set_framesize(s, (framesize_t)val);
|
||||
}
|
||||
else if (!strcmp(variable, "quality"))
|
||||
else if (variable.compareTo("quality") == 0)
|
||||
res = s->set_quality(s, val);
|
||||
else if (!strcmp(variable, "contrast"))
|
||||
else if (variable.compareTo("contrast") == 0)
|
||||
res = s->set_contrast(s, val);
|
||||
else if (!strcmp(variable, "brightness"))
|
||||
else if (variable.compareTo("brightness") == 0)
|
||||
res = s->set_brightness(s, val);
|
||||
else if (!strcmp(variable, "saturation"))
|
||||
else if (variable.compareTo("saturation") == 0)
|
||||
res = s->set_saturation(s, val);
|
||||
else if (!strcmp(variable, "gainceiling"))
|
||||
else if (variable.compareTo("gainceiling") == 0)
|
||||
res = s->set_gainceiling(s, (gainceiling_t)val);
|
||||
else if (!strcmp(variable, "colorbar"))
|
||||
else if (variable.compareTo("colorbar") == 0)
|
||||
res = s->set_colorbar(s, val);
|
||||
else if (!strcmp(variable, "awb"))
|
||||
else if (variable.compareTo("awb") == 0)
|
||||
res = s->set_whitebal(s, val);
|
||||
else if (!strcmp(variable, "agc"))
|
||||
else if (variable.compareTo("agc") == 0)
|
||||
res = s->set_gain_ctrl(s, val);
|
||||
else if (!strcmp(variable, "aec"))
|
||||
else if (variable.compareTo("aec") == 0)
|
||||
res = s->set_exposure_ctrl(s, val);
|
||||
else if (!strcmp(variable, "hmirror"))
|
||||
else if (variable.compareTo("hmirror") == 0)
|
||||
res = s->set_hmirror(s, val);
|
||||
else if (!strcmp(variable, "vflip"))
|
||||
else if (variable.compareTo("vFlip") == 0)
|
||||
res = s->set_vflip(s, val);
|
||||
else if (!strcmp(variable, "awb_gain"))
|
||||
else if (variable.compareTo("awb_gain") == 0)
|
||||
res = s->set_awb_gain(s, val);
|
||||
else if (!strcmp(variable, "agc_gain"))
|
||||
else if (variable.compareTo("agc_gain") == 0)
|
||||
res = s->set_agc_gain(s, val);
|
||||
else if (!strcmp(variable, "aec_value"))
|
||||
else if (variable.compareTo("aec_value") == 0)
|
||||
res = s->set_aec_value(s, val);
|
||||
else if (!strcmp(variable, "aec2"))
|
||||
else if (variable.compareTo("aec2") == 0)
|
||||
res = s->set_aec2(s, val);
|
||||
else if (!strcmp(variable, "dcw"))
|
||||
else if (variable.compareTo("dcw") == 0)
|
||||
res = s->set_dcw(s, val);
|
||||
else if (!strcmp(variable, "bpc"))
|
||||
else if (variable.compareTo("bpc") == 0)
|
||||
res = s->set_bpc(s, val);
|
||||
else if (!strcmp(variable, "wpc"))
|
||||
else if (variable.compareTo("wpc") == 0)
|
||||
res = s->set_wpc(s, val);
|
||||
else if (!strcmp(variable, "raw_gma"))
|
||||
else if (variable.compareTo("raw_gma") == 0)
|
||||
res = s->set_raw_gma(s, val);
|
||||
else if (!strcmp(variable, "lenc"))
|
||||
else if (variable.compareTo("lenc") == 0)
|
||||
res = s->set_lenc(s, val);
|
||||
else if (!strcmp(variable, "special_effect"))
|
||||
else if (variable.compareTo("special_effect") == 0)
|
||||
res = s->set_special_effect(s, val);
|
||||
else if (!strcmp(variable, "wb_mode"))
|
||||
else if (variable.compareTo("wb_mode") == 0)
|
||||
res = s->set_wb_mode(s, val);
|
||||
else if (!strcmp(variable, "ae_level"))
|
||||
else if (variable.compareTo("ae_level") == 0)
|
||||
res = s->set_ae_level(s, val);
|
||||
else if (!strcmp(variable, "rotate"))
|
||||
else if (variable.compareTo("rotate") == 0)
|
||||
myRotation = val;
|
||||
else if (!strcmp(variable, "face_detect"))
|
||||
{
|
||||
detection_enabled = val;
|
||||
if (!detection_enabled)
|
||||
{
|
||||
recognition_enabled = 0;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(variable, "lamp") && (lampVal != -1))
|
||||
else if (variable.compareTo("lamp") == 0)
|
||||
{
|
||||
lampVal = constrain(val, 0, 100);
|
||||
setLamp(lampVal);
|
||||
}
|
||||
else if (!strcmp(variable, "save_prefs"))
|
||||
else if (variable.compareTo("save_prefs") == 0)
|
||||
{
|
||||
if (filesystem)
|
||||
savePrefs(SPIFFS);
|
||||
}
|
||||
else if (!strcmp(variable, "clear_prefs"))
|
||||
else if (variable.compareTo("clear_prefs") == 0)
|
||||
{
|
||||
if (filesystem)
|
||||
removePrefs(SPIFFS);
|
||||
}
|
||||
else if (!strcmp(variable, "reboot"))
|
||||
else if (variable.compareTo("reboot") == 0)
|
||||
|
||||
{
|
||||
request->send(200, "text/plain", "Rebooting...");
|
||||
Serial.print("REBOOT requested");
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
|
@ -299,24 +207,34 @@ static esp_err_t cmd_handler(httpd_req_t *req)
|
|||
delay(150);
|
||||
Serial.print('.');
|
||||
}
|
||||
Serial.printf(" Thats all folks!\n\n");
|
||||
Serial.printf(" Thats all folks!\r\n\r\n");
|
||||
ESP.restart();
|
||||
}
|
||||
else if (variable.compareTo("clear_wifi") == 0)
|
||||
{
|
||||
request->send(200, "text/plain", "Reseting WiFi...");
|
||||
Serial.println("Wifi reset requested");
|
||||
resetWiFiConfig();
|
||||
}
|
||||
else
|
||||
{
|
||||
res = -1;
|
||||
}
|
||||
if (res)
|
||||
{
|
||||
return httpd_resp_send_500(req);
|
||||
Serial.print("Unable to determine command: ");
|
||||
Serial.println(variable);
|
||||
|
||||
request->send(404, "text/plain", "Invalid parameters");
|
||||
return;
|
||||
}
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
return httpd_resp_send(req, NULL, 0);
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
|
||||
static esp_err_t status_handler(httpd_req_t *req)
|
||||
void status_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
static char json_response[1024];
|
||||
char json_response[1024];
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
char *p = json_response;
|
||||
*p++ = '{';
|
||||
|
@ -346,325 +264,275 @@ static esp_err_t status_handler(httpd_req_t *req)
|
|||
p += sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
|
||||
p += sprintf(p, "\"dcw\":%u,", s->status.dcw);
|
||||
p += sprintf(p, "\"colorbar\":%u,", s->status.colorbar);
|
||||
p += sprintf(p, "\"cam_name\":\"%s\",", myName);
|
||||
p += sprintf(p, "\"cam_name\":\"%s\",", camera_name);
|
||||
p += sprintf(p, "\"code_ver\":\"%s\",", myVer);
|
||||
p += sprintf(p, "\"rotate\":\"%d\",", myRotation);
|
||||
p += sprintf(p, "\"stream_url\":\"%s\"", streamURL);
|
||||
*p++ = '}';
|
||||
*p++ = 0;
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
return httpd_resp_send(req, json_response, strlen(json_response));
|
||||
|
||||
request->send(200, "application/json", json_response);
|
||||
}
|
||||
|
||||
static esp_err_t favicon_16x16_handler(httpd_req_t *req)
|
||||
void favicon_16x16_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
httpd_resp_set_type(req, "image/png");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, (const char *)favicon_16x16_png, favicon_16x16_png_len);
|
||||
request->send(200, "image/png", (const char *)favicon_16x16_png);
|
||||
}
|
||||
|
||||
static esp_err_t favicon_32x32_handler(httpd_req_t *req)
|
||||
void favicon_32x32_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
httpd_resp_set_type(req, "image/png");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, (const char *)favicon_32x32_png, favicon_32x32_png_len);
|
||||
request->send(200, "image/png", (const char *)favicon_32x32_png);
|
||||
}
|
||||
|
||||
static esp_err_t favicon_ico_handler(httpd_req_t *req)
|
||||
void favicon_ico_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
httpd_resp_set_type(req, "image/x-icon");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, (const char *)favicon_ico, favicon_ico_len);
|
||||
request->send(200, "image/png", (const char *)favicon_ico);
|
||||
}
|
||||
|
||||
static esp_err_t logo_svg_handler(httpd_req_t *req)
|
||||
void logo_svg_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
httpd_resp_set_type(req, "image/svg+xml");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, (const char *)logo_svg, logo_svg_len);
|
||||
request->send(200, "image/svg+xml", (const char *)logo_svg);
|
||||
}
|
||||
|
||||
static esp_err_t dump_handler(httpd_req_t *req)
|
||||
void dump_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
flashLED(75);
|
||||
Serial.println("\nDump Requested");
|
||||
Serial.println("\r\nDump Requested");
|
||||
Serial.print("Preferences file: ");
|
||||
dumpPrefs(SPIFFS);
|
||||
static char dumpOut[1200] = "";
|
||||
char dumpOut[1200] = "";
|
||||
char *d = dumpOut;
|
||||
// Header
|
||||
d += sprintf(d, "<html><head><meta charset=\"utf-8\">\n");
|
||||
d += sprintf(d, "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n");
|
||||
d += sprintf(d, "<title>%s - Status</title>\n", myName);
|
||||
d += sprintf(d, "<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/favicon-32x32.png\">\n");
|
||||
d += sprintf(d, "<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/favicon-16x16.png\">\n");
|
||||
d += sprintf(d, "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\n");
|
||||
d += sprintf(d, "</head>\n<body>\n");
|
||||
d += sprintf(d, "<img src=\"/logo.svg\" style=\"position: relative; float: right;\">\n");
|
||||
d += sprintf(d, "<h1>ESP32 Cam Webserver</h1>\n");
|
||||
d += sprintf(d, "<html><head><meta charset=\"utf-8\">\r\n");
|
||||
d += sprintf(d, "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\r\n");
|
||||
d += sprintf(d, "<title>%s - Status</title>\r\n", camera_name);
|
||||
d += sprintf(d, "<link rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/favicon-32x32.png\">\r\n");
|
||||
d += sprintf(d, "<link rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/favicon-16x16.png\">\r\n");
|
||||
d += sprintf(d, "<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">\r\n");
|
||||
d += sprintf(d, "</head>\r\n<body>\r\n");
|
||||
d += sprintf(d, "<img src=\"/logo.svg\" style=\"position: relative; float: right;\">\r\n");
|
||||
d += sprintf(d, "<h1>ESP32 Cam Webserver</h1>\r\n");
|
||||
// Module
|
||||
d += sprintf(d, "Name: %s<br>\n", myName);
|
||||
Serial.printf("Name: %s\n", myName);
|
||||
d += sprintf(d, "Firmware: %s (base: %s)<br>\n", myVer, baseVersion);
|
||||
Serial.printf("Firmware: %s (base: %s)\n", myVer, baseVersion);
|
||||
d += sprintf(d, "Name: %s<br>\r\n", camera_name);
|
||||
Serial.printf("Name: %s\r\n", camera_name);
|
||||
d += sprintf(d, "Firmware: %s (base: %s)<br>\r\n", myVer, baseVersion);
|
||||
Serial.printf("Firmware: %s (base: %s)\r\n", myVer, baseVersion);
|
||||
float sketchPct = 100 * sketchSize / sketchSpace;
|
||||
d += sprintf(d, "Sketch Size: %i (total: %i, %.1f%% used)<br>\n", sketchSize, sketchSpace, sketchPct);
|
||||
Serial.printf("Sketch Size: %i (total: %i, %.1f%% used)\n", sketchSize, sketchSpace, sketchPct);
|
||||
d += sprintf(d, "MD5: %s<br>\n", sketchMD5.c_str());
|
||||
Serial.printf("MD5: %s\n", sketchMD5.c_str());
|
||||
d += sprintf(d, "ESP sdk: %s<br>\n", ESP.getSdkVersion());
|
||||
Serial.printf("ESP sdk: %s\n", ESP.getSdkVersion());
|
||||
d += sprintf(d, "Sketch Size: %i (total: %i, %.1f%% used)<br>\r\n", sketchSize, sketchSpace, sketchPct);
|
||||
Serial.printf("Sketch Size: %i (total: %i, %.1f%% used)\r\n", sketchSize, sketchSpace, sketchPct);
|
||||
d += sprintf(d, "MD5: %s<br>\r\n", sketchMD5.c_str());
|
||||
Serial.printf("MD5: %s\r\n", sketchMD5.c_str());
|
||||
d += sprintf(d, "ESP sdk: %s<br>\r\n", ESP.getSdkVersion());
|
||||
Serial.printf("ESP sdk: %s\r\n", ESP.getSdkVersion());
|
||||
// Network
|
||||
d += sprintf(d, "<h2>WiFi</h2>\n");
|
||||
if (accesspoint)
|
||||
{
|
||||
if (captivePortal)
|
||||
{
|
||||
d += sprintf(d, "Mode: AccessPoint with captive portal<br>\n");
|
||||
Serial.printf("Mode: AccessPoint with captive portal\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
d += sprintf(d, "Mode: AccessPoint<br>\n");
|
||||
Serial.printf("Mode: AccessPoint\n");
|
||||
}
|
||||
d += sprintf(d, "SSID: %s<br>\n", apName);
|
||||
Serial.printf("SSID: %s\n", apName);
|
||||
}
|
||||
else
|
||||
{
|
||||
d += sprintf(d, "Mode: Client<br>\n");
|
||||
Serial.printf("Mode: Client\n");
|
||||
d += sprintf(d, "<h2>WiFi</h2>\r\n");
|
||||
d += sprintf(d, "Mode: Client<br>\r\n");
|
||||
Serial.printf("Mode: Client\r\n");
|
||||
String ssidName = WiFi.SSID();
|
||||
d += sprintf(d, "SSID: %s<br>\n", ssidName.c_str());
|
||||
Serial.printf("Ssid: %s\n", ssidName.c_str());
|
||||
d += sprintf(d, "Rssi: %i<br>\n", WiFi.RSSI());
|
||||
Serial.printf("Rssi: %i\n", WiFi.RSSI());
|
||||
d += sprintf(d, "SSID: %s<br>\r\n", ssidName.c_str());
|
||||
Serial.printf("Ssid: %s\r\n", ssidName.c_str());
|
||||
d += sprintf(d, "Rssi: %i<br>\r\n", WiFi.RSSI());
|
||||
Serial.printf("Rssi: %i\r\n", WiFi.RSSI());
|
||||
String bssid = WiFi.BSSIDstr();
|
||||
d += sprintf(d, "BSSID: %s<br>\n", bssid.c_str());
|
||||
Serial.printf("BSSID: %s\n", bssid.c_str());
|
||||
}
|
||||
d += sprintf(d, "IP address: %d.%d.%d.%d<br>\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
Serial.printf("IP address: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
if (!accesspoint)
|
||||
{
|
||||
d += sprintf(d, "Netmask: %d.%d.%d.%d<br>\n", net[0], net[1], net[2], net[3]);
|
||||
Serial.printf("Netmask: %d.%d.%d.%d\n", net[0], net[1], net[2], net[3]);
|
||||
d += sprintf(d, "Gateway: %d.%d.%d.%d<br>\n", gw[0], gw[1], gw[2], gw[3]);
|
||||
Serial.printf("Gateway: %d.%d.%d.%d\n", gw[0], gw[1], gw[2], gw[3]);
|
||||
}
|
||||
d += sprintf(d, "Http port: %i<br>\n", httpPort);
|
||||
Serial.printf("Http port: %i\n", httpPort);
|
||||
d += sprintf(d, "BSSID: %s<br>\r\n", bssid.c_str());
|
||||
Serial.printf("BSSID: %s\r\n", bssid.c_str());
|
||||
|
||||
d += sprintf(d, "IP address: %d.%d.%d.%d<br>\r\n", espIP[0], espIP[1], espIP[2], espIP[3]);
|
||||
Serial.printf("IP address: %d.%d.%d.%d\r\n", espIP[0], espIP[1], espIP[2], espIP[3]);
|
||||
d += sprintf(d, "Http port: %i<br>\r\n", httpPort);
|
||||
Serial.printf("Http port: %i\r\n", httpPort);
|
||||
byte mac[6];
|
||||
WiFi.macAddress(mac);
|
||||
d += sprintf(d, "MAC: %02X:%02X:%02X:%02X:%02X:%02X<br>\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
Serial.printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
d += sprintf(d, "MAC: %02X:%02X:%02X:%02X:%02X:%02X<br>\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
Serial.printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
|
||||
// System
|
||||
d += sprintf(d, "<h2>System</h2>\n");
|
||||
d += sprintf(d, "<h2>System</h2>\r\n");
|
||||
int64_t sec = esp_timer_get_time() / 1000000;
|
||||
int64_t upDays = int64_t(floor(sec / 86400));
|
||||
int upHours = int64_t(floor(sec / 3600)) % 24;
|
||||
int upMin = int64_t(floor(sec / 60)) % 60;
|
||||
int upSec = sec % 60;
|
||||
d += sprintf(d, "Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)<br>\n", upDays, upHours, upMin, upSec);
|
||||
Serial.printf("Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)\n", upDays, upHours, upMin, upSec);
|
||||
d += sprintf(d, "Freq: %i MHz<br>\n", ESP.getCpuFreqMHz());
|
||||
Serial.printf("Freq: %i MHz\n", ESP.getCpuFreqMHz());
|
||||
d += sprintf(d, "Heap: %i, free: %i, min free: %i, max block: %i<br>\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
|
||||
Serial.printf("Heap: %i, free: %i, min free: %i, max block: %i\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
|
||||
d += sprintf(d, "Psram: %i, free: %i, min free: %i, max block: %i<br>\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram());
|
||||
Serial.printf("Psram: %i, free: %i, min free: %i, max block: %i\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram());
|
||||
d += sprintf(d, "Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)<br>\r\n", upDays, upHours, upMin, upSec);
|
||||
Serial.printf("Up: %" PRId64 ":%02i:%02i:%02i (d:h:m:s)\r\n", upDays, upHours, upMin, upSec);
|
||||
d += sprintf(d, "Freq: %i MHz<br>\r\n", ESP.getCpuFreqMHz());
|
||||
Serial.printf("Freq: %i MHz\r\n", ESP.getCpuFreqMHz());
|
||||
d += sprintf(d, "Heap: %i, free: %i, min free: %i, max block: %i<br>\r\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
|
||||
Serial.printf("Heap: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getHeapSize(), ESP.getFreeHeap(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap());
|
||||
d += sprintf(d, "Psram: %i, free: %i, min free: %i, max block: %i<br>\r\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram());
|
||||
Serial.printf("Psram: %i, free: %i, min free: %i, max block: %i\r\n", ESP.getPsramSize(), ESP.getFreePsram(), ESP.getMinFreePsram(), ESP.getMaxAllocPsram());
|
||||
if (filesystem)
|
||||
{
|
||||
d += sprintf(d, "Spiffs: %i, used: %i<br>\n", SPIFFS.totalBytes(), SPIFFS.usedBytes());
|
||||
Serial.printf("Spiffs: %i, used: %i\n", SPIFFS.totalBytes(), SPIFFS.usedBytes());
|
||||
d += sprintf(d, "Spiffs: %i, used: %i<br>\r\n", SPIFFS.totalBytes(), SPIFFS.usedBytes());
|
||||
Serial.printf("Spiffs: %i, used: %i\r\n", SPIFFS.totalBytes(), SPIFFS.usedBytes());
|
||||
}
|
||||
|
||||
// Footer
|
||||
d += sprintf(d, "<br><div class=\"input-group\">\n");
|
||||
d += sprintf(d, "<button title=\"Refresh this page\" onclick=\"location.replace(document.URL)\">Refresh</button>\n");
|
||||
d += sprintf(d, "<button title=\"Close this page\" onclick=\"javascript:window.close()\">Close</button>\n");
|
||||
d += sprintf(d, "</div>\n</body>\n</html>\n");
|
||||
d += sprintf(d, "<br><div class=\"input-group\">\r\n");
|
||||
d += sprintf(d, "<button title=\"Refresh this page\" onclick=\"location.replace(document.URL)\">Refresh</button>\r\n");
|
||||
d += sprintf(d, "<button title=\"Close this page\" onclick=\"javascript:window.close()\">Close</button>\r\n");
|
||||
d += sprintf(d, "</div>\r\n</body>\r\n</html>\r\n");
|
||||
*d++ = 0;
|
||||
httpd_resp_set_type(req, "text/html");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, dumpOut, strlen(dumpOut));
|
||||
|
||||
request->send(200, "image/html", dumpOut);
|
||||
}
|
||||
|
||||
static esp_err_t style_handler(httpd_req_t *req)
|
||||
void style_handler(AsyncWebServerRequest *request)
|
||||
{
|
||||
httpd_resp_set_type(req, "text/css");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, (const char *)style_css, style_css_len);
|
||||
request->send(200, "text/css", (const char *)style_css);
|
||||
}
|
||||
|
||||
static esp_err_t index_handler(httpd_req_t *req)
|
||||
void handleIndex(AsyncWebServerRequest *request)
|
||||
{
|
||||
|
||||
flashLED(150);
|
||||
// See if we have a specific target (full/simple/portal) and serve as appropriate
|
||||
String view = default_index;
|
||||
|
||||
if (request->hasArg("view"))
|
||||
{
|
||||
view = request->arg("view").c_str();
|
||||
}
|
||||
|
||||
if (strncmp(view.c_str(), "simple", sizeof(view)) == 0)
|
||||
{
|
||||
Serial.println("Simple index page requested");
|
||||
request->send_P(200, "text/html", (const char *)index_simple_html);
|
||||
return;
|
||||
}
|
||||
else if (strncmp(view.c_str(), "full", sizeof(view)) == 0)
|
||||
{
|
||||
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
|
||||
if (s->id.PID == OV3660_PID)
|
||||
{
|
||||
Serial.println("Full OV3660 index page requested");
|
||||
request->send_P(200, "text/html", (const char *)index_ov3660_html);
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Full OV2640 index page requested");
|
||||
request->send_P(200, "text/html",(const char *)index_ov2640_html);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.print("Unknown page requested: ");
|
||||
Serial.println(view);
|
||||
request->send(404, "text/plain", "Unknown page requested");
|
||||
}
|
||||
|
||||
void handleFirmware(AsyncWebServerRequest *request)
|
||||
{
|
||||
char *buf;
|
||||
size_t buf_len;
|
||||
char view[32] = {
|
||||
0,
|
||||
};
|
||||
|
||||
flashLED(75);
|
||||
// See if we have a specific target (full/simple/portal) and serve as appropriate
|
||||
buf_len = httpd_req_get_url_query_len(req) + 1;
|
||||
if (buf_len > 1)
|
||||
|
||||
Serial.println("Firmware page requested");
|
||||
request->send(200, "text/html", firmware_html.c_str());
|
||||
}
|
||||
|
||||
String getHTMLHead()
|
||||
{
|
||||
String header = F("<!DOCTYPE html><html lang=\"en\"><head>");
|
||||
header += F("<link href=\"/local.css\" rel=\"stylesheet\">");
|
||||
header += F("</head>");
|
||||
header += F("<body>");
|
||||
return header;
|
||||
}
|
||||
|
||||
String getHTMLFoot()
|
||||
{
|
||||
return F("</body></html>");
|
||||
}
|
||||
void handleUpdate(AsyncWebServerRequest *request)
|
||||
{
|
||||
String response_message;
|
||||
response_message.reserve(1000);
|
||||
response_message = getHTMLHead();
|
||||
response_message += "<script> function notify_update() {document.getElementById(\"update\").innerHTML = \"<h2>Updating...</h2>\"\; } </script>";
|
||||
response_message += "Firmware = *.esp32.bin<br>SPIFFS = *.spiffs.bin<br> \
|
||||
<form method='POST' action='/doUpdate' enctype='multipart/form-data' target='_self' onsubmit='notify_update()'> \
|
||||
<input type='file' name='update'><br> \
|
||||
<input type='submit' value='Do update'></form> \
|
||||
<div id=\"update\"></div>";
|
||||
response_message += getHTMLFoot();
|
||||
request->send(200, "text/html", response_message);
|
||||
};
|
||||
|
||||
void handleDoUpdate(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)
|
||||
{
|
||||
updating = true;
|
||||
delay(500);
|
||||
|
||||
if (!index)
|
||||
{
|
||||
buf = (char *)malloc(buf_len);
|
||||
if (!buf)
|
||||
// check file names for type
|
||||
int cmd = (filename.indexOf(F(".spiffs.bin")) > -1) ? U_SPIFFS : U_FLASH;
|
||||
if (cmd == U_FLASH && !(filename.indexOf(F("esp32.bin")) > -1))
|
||||
return; // wrong image for ESP32
|
||||
if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd))
|
||||
{
|
||||
httpd_resp_send_500(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK)
|
||||
{
|
||||
if (httpd_query_key_value(buf, "view", view, sizeof(view)) == ESP_OK)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buf);
|
||||
httpd_resp_send_404(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free(buf);
|
||||
httpd_resp_send_404(req);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no target specified; default.
|
||||
strcpy(view, default_index);
|
||||
// If captive portal is active send that instead
|
||||
if (captivePortal)
|
||||
{
|
||||
strcpy(view, "portal");
|
||||
Update.printError(Serial);
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp(view, "simple", sizeof(view)) == 0)
|
||||
if (Update.write(data, len) != len)
|
||||
{
|
||||
Serial.println("Simple index page requested");
|
||||
httpd_resp_set_type(req, "text/html");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, (const char *)index_simple_html, index_simple_html_len);
|
||||
Update.printError(Serial);
|
||||
}
|
||||
else if (strncmp(view, "full", sizeof(view)) == 0)
|
||||
|
||||
if (final)
|
||||
{
|
||||
Serial.println("Full index page requested");
|
||||
httpd_resp_set_type(req, "text/html");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
if (s->id.PID == OV3660_PID)
|
||||
if (!Update.end(true))
|
||||
{
|
||||
return httpd_resp_send(req, (const char *)index_ov3660_html, index_ov3660_html_len);
|
||||
}
|
||||
return httpd_resp_send(req, (const char *)index_ov2640_html, index_ov2640_html_len);
|
||||
}
|
||||
else if (strncmp(view, "portal", sizeof(view)) == 0)
|
||||
{
|
||||
//Prototype captive portal landing page.
|
||||
Serial.println("Portal page requested");
|
||||
std::string s(portal_html);
|
||||
size_t index;
|
||||
while ((index = s.find("<APPURL>")) != std::string::npos)
|
||||
s.replace(index, strlen("<APPURL>"), httpURL);
|
||||
while ((index = s.find("<STREAMURL>")) != std::string::npos)
|
||||
s.replace(index, strlen("<STREAMURL>"), streamURL);
|
||||
while ((index = s.find("<CAMNAME>")) != std::string::npos)
|
||||
s.replace(index, strlen("<CAMNAME>"), myName);
|
||||
httpd_resp_set_type(req, "text/html");
|
||||
httpd_resp_set_hdr(req, "Content-Encoding", "identity");
|
||||
return httpd_resp_send(req, (const char *)s.c_str(), s.length());
|
||||
Update.printError(Serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("Unknown page requested: ");
|
||||
Serial.println(view);
|
||||
httpd_resp_send_404(req);
|
||||
return ESP_FAIL;
|
||||
String response_message;
|
||||
response_message.reserve(1000);
|
||||
response_message = getHTMLHead();
|
||||
response_message += "<h2>Please wait while the device reboots</h2> <meta http-equiv=\"refresh\" content=\"20;url=/\" />";
|
||||
response_message += getHTMLFoot();
|
||||
AsyncWebServerResponse *response = request->beginResponse(200, "text/html", response_message);
|
||||
response->addHeader("Refresh", "20");
|
||||
response->addHeader("Location", "/");
|
||||
request->send(response);
|
||||
delay(100);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startCameraServer()
|
||||
{
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.max_uri_handlers = 12; // we use more than the default 8 (on port 80)
|
||||
Serial.printf("Starting web server on port: '%d'\r\n", httpPort);
|
||||
|
||||
httpd_uri_t index_uri = {
|
||||
.uri = "/",
|
||||
.method = HTTP_GET,
|
||||
.handler = index_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t status_uri = {
|
||||
.uri = "/status",
|
||||
.method = HTTP_GET,
|
||||
.handler = status_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t cmd_uri = {
|
||||
.uri = "/control",
|
||||
.method = HTTP_GET,
|
||||
.handler = cmd_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t capture_uri = {
|
||||
.uri = "/capture",
|
||||
.method = HTTP_GET,
|
||||
.handler = capture_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t style_uri = {
|
||||
.uri = "/style.css",
|
||||
.method = HTTP_GET,
|
||||
.handler = style_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t favicon_16x16_uri = {
|
||||
.uri = "/favicon-16x16.png",
|
||||
.method = HTTP_GET,
|
||||
.handler = favicon_16x16_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t favicon_32x32_uri = {
|
||||
.uri = "/favicon-32x32.png",
|
||||
.method = HTTP_GET,
|
||||
.handler = favicon_32x32_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t favicon_ico_uri = {
|
||||
.uri = "/favicon.ico",
|
||||
.method = HTTP_GET,
|
||||
.handler = favicon_ico_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t logo_svg_uri = {
|
||||
.uri = "/logo.svg",
|
||||
.method = HTTP_GET,
|
||||
.handler = logo_svg_handler,
|
||||
.user_ctx = NULL};
|
||||
httpd_uri_t dump_uri = {
|
||||
.uri = "/dump",
|
||||
.method = HTTP_GET,
|
||||
.handler = dump_handler,
|
||||
.user_ctx = NULL};
|
||||
appServer.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleIndex(request);
|
||||
});
|
||||
appServer.on("/firmware", HTTP_GET, handleFirmware);
|
||||
appServer.on("/status", HTTP_GET, status_handler);
|
||||
appServer.on("/control", HTTP_GET, cmd_handler);
|
||||
appServer.on("/capture", HTTP_GET, capture_handler);
|
||||
appServer.on("/style.css", HTTP_GET, style_handler);
|
||||
appServer.on("/favicon-16x16.png", HTTP_GET, favicon_16x16_handler);
|
||||
appServer.on("/favicon-32x32.png", HTTP_GET, favicon_32x32_handler);
|
||||
appServer.on("/favicon.ico", HTTP_GET, favicon_ico_handler);
|
||||
appServer.on("/logo.svg", HTTP_GET, logo_svg_handler);
|
||||
appServer.on("/dump", HTTP_GET, dump_handler);
|
||||
/*handling uploading firmware file */
|
||||
appServer.on("/update", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
handleUpdate(request);
|
||||
});
|
||||
appServer.on(
|
||||
"/doUpdate", HTTP_POST, [](AsyncWebServerRequest *request) {}, [](AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final) { handleDoUpdate(request, filename, index, data, len, final); });
|
||||
|
||||
config.server_port = httpPort;
|
||||
config.ctrl_port = httpPort;
|
||||
Serial.printf("Starting web server on port: '%d'\n", config.server_port);
|
||||
if (httpd_start(&camera_httpd, &config) == ESP_OK)
|
||||
{
|
||||
// Note; config.max_uri_handlers (above) must be >= the number of handlers
|
||||
httpd_register_uri_handler(camera_httpd, &index_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &cmd_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &status_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &capture_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &style_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &favicon_16x16_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &favicon_32x32_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &favicon_ico_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &logo_svg_uri);
|
||||
httpd_register_uri_handler(camera_httpd, &dump_uri);
|
||||
}
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
||||
appServer.begin();
|
||||
Serial.println("Web server started!");
|
||||
|
||||
sprintf(httpURL, "http://%d.%d.%d.%d:%d/", espIP[0], espIP[1], espIP[2], espIP[3], httpPort);
|
||||
}
|
||||
|
|
|
@ -1,78 +1,42 @@
|
|||
#include <Arduino.h>
|
||||
#include "esp_camera.h"
|
||||
#include <WiFi.h>
|
||||
#include <DNSServer.h>
|
||||
#include "esp_camera.h"
|
||||
#include "src/version.h"
|
||||
#include "myconfig.h"
|
||||
#include "camera_pins.h"
|
||||
#include "storage.h"
|
||||
#include <WiFiClient.h>
|
||||
#include <WebServer.h>
|
||||
|
||||
#define APP_CPU 1
|
||||
#define PRO_CPU 0
|
||||
// IP address, Netmask and Gateway, populated when connected
|
||||
extern IPAddress espIP;
|
||||
extern IPAddress espSubnet;
|
||||
extern IPAddress espGateway;
|
||||
|
||||
// The app and stream URLs
|
||||
extern char httpURL[64];
|
||||
extern char streamURL[64];
|
||||
extern char camera_name[];
|
||||
|
||||
extern void startWiFi();
|
||||
extern void startCameraServer();
|
||||
extern void startStreamServer();
|
||||
extern void startMQTTClient();
|
||||
extern void handleMQTT();
|
||||
|
||||
// Primary config, or defaults.
|
||||
#if __has_include("myconfig.h")
|
||||
#include "myconfig.h"
|
||||
#else
|
||||
#warning "Using Defaults: Copy myconfig.sample.h to myconfig.h and edit that to use your own settings"
|
||||
#define WIFI_AP_ENABLE
|
||||
#define CAMERA_MODEL_AI_THINKER
|
||||
struct station
|
||||
{
|
||||
const char ssid[64];
|
||||
const char password[64];
|
||||
const bool dhcp;
|
||||
} stationList[] = {{"ESP32-CAM-CONNECT", "InsecurePassword", true}};
|
||||
#endif
|
||||
|
||||
// Upstream version string
|
||||
#include "src/version.h"
|
||||
|
||||
// Pin Mappings
|
||||
#include "camera_pins.h"
|
||||
|
||||
// Internal filesystem (SPIFFS)
|
||||
// used for non-volatile camera settings and face DB store
|
||||
#include "storage.h"
|
||||
|
||||
// Sketch Info
|
||||
int sketchSize;
|
||||
int sketchSpace;
|
||||
String sketchMD5;
|
||||
|
||||
// Start with accesspoint mode disabled, wifi setup will activate it if
|
||||
// no known networks are found, and WIFI_AP_ENABLE has been defined
|
||||
bool accesspoint = false;
|
||||
|
||||
// IP address, Netmask and Gateway, populated when connected
|
||||
IPAddress ip;
|
||||
IPAddress net;
|
||||
IPAddress gw;
|
||||
|
||||
// Declare external function from app_httpd.cpp
|
||||
extern void startCameraServer();
|
||||
// Declare external function from esp32-streamserver.cpp
|
||||
extern void startStreamServer();
|
||||
// Declare external function from esp32-streamserver.cpp
|
||||
void startMQTTClient(const char *, int, const char *, const char *, const void *);
|
||||
|
||||
// A Name for the Camera. (set in myconfig.h)
|
||||
#if defined(CAM_NAME)
|
||||
char myName[] = CAM_NAME;
|
||||
#else
|
||||
char myName[] = "ESP32 camera server";
|
||||
#endif
|
||||
|
||||
#if !defined(WIFI_WATCHDOG)
|
||||
#define WIFI_WATCHDOG 5000
|
||||
#endif
|
||||
|
||||
// Number of known networks in stationList[]
|
||||
int stationCount = sizeof(stationList) / sizeof(stationList[0]);
|
||||
|
||||
// If we have AP mode enabled, ignore first entry in the stationList[]
|
||||
#if defined(WIFI_AP_ENABLE)
|
||||
int firstStation = 1;
|
||||
#else
|
||||
int firstStation = 0;
|
||||
#endif
|
||||
|
||||
// Select bvetween full and simple index as the default.
|
||||
#if defined(DEFAULT_INDEX_FULL)
|
||||
char default_index[] = "full";
|
||||
|
@ -80,16 +44,6 @@ char default_index[] = "full";
|
|||
char default_index[] = "simple";
|
||||
#endif
|
||||
|
||||
// DNS server
|
||||
const byte DNS_PORT = 53;
|
||||
DNSServer dnsServer;
|
||||
bool captivePortal = false;
|
||||
char apName[64] = "Undefined";
|
||||
|
||||
// The app and stream URLs
|
||||
char httpURL[64] = {"Undefined"};
|
||||
char streamURL[64] = {"Undefined"};
|
||||
|
||||
// This will be displayed to identify the firmware
|
||||
char myVer[] PROGMEM = __DATE__ " @ " __TIME__;
|
||||
|
||||
|
@ -124,18 +78,6 @@ bool filesystem = false;
|
|||
bool filesystem = true;
|
||||
#endif
|
||||
|
||||
#if defined(FACE_DETECTION)
|
||||
int8_t detection_enabled = 1;
|
||||
#if defined(FACE_RECOGNITION)
|
||||
int8_t recognition_enabled = 1;
|
||||
#else
|
||||
int8_t recognition_enabled = 0;
|
||||
#endif
|
||||
#else
|
||||
int8_t detection_enabled = 0;
|
||||
int8_t recognition_enabled = 0;
|
||||
#endif
|
||||
|
||||
// Debug Data for stream and capture
|
||||
#if defined(DEBUG_DEFAULT_ON)
|
||||
bool debugData = true;
|
||||
|
@ -174,200 +116,6 @@ void setLamp(int newVal)
|
|||
Serial.println(brightness);
|
||||
}
|
||||
}
|
||||
|
||||
void WifiSetup()
|
||||
{
|
||||
// Feedback that we are now attempting to connect
|
||||
flashLED(300);
|
||||
delay(100);
|
||||
flashLED(300);
|
||||
Serial.println("Starting WiFi");
|
||||
Serial.print("Known external SSIDs: ");
|
||||
if (stationCount > firstStation)
|
||||
{
|
||||
for (int i = firstStation; i < stationCount; i++)
|
||||
Serial.printf(" '%s'", stationList[i].ssid);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("None");
|
||||
}
|
||||
Serial.println();
|
||||
byte mac[6];
|
||||
WiFi.macAddress(mac);
|
||||
Serial.printf("MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
|
||||
int bestStation = -1;
|
||||
long bestRSSI = -1024;
|
||||
if (stationCount > firstStation)
|
||||
{
|
||||
// We have a list to scan
|
||||
Serial.printf("Scanning local Wifi Networks\n");
|
||||
int stationsFound = WiFi.scanNetworks();
|
||||
Serial.printf("%i networks found\n", stationsFound);
|
||||
if (stationsFound > 0)
|
||||
{
|
||||
for (int i = 0; i < stationsFound; ++i)
|
||||
{
|
||||
// Print SSID and RSSI for each network found
|
||||
String thisSSID = WiFi.SSID(i);
|
||||
int thisRSSI = WiFi.RSSI(i);
|
||||
Serial.printf("%3i : %s (%i)", i + 1, thisSSID.c_str(), thisRSSI);
|
||||
// Scan our list of known external stations
|
||||
for (int sta = firstStation; sta < stationCount; sta++)
|
||||
{
|
||||
if (strcmp(stationList[sta].ssid, thisSSID.c_str()) == 0)
|
||||
{
|
||||
Serial.print(" - Known!");
|
||||
// Chose the strongest RSSI seen
|
||||
if (thisRSSI > bestRSSI)
|
||||
{
|
||||
bestStation = sta;
|
||||
bestRSSI = thisRSSI;
|
||||
}
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// No list to scan, therefore we are an accesspoint
|
||||
accesspoint = true;
|
||||
}
|
||||
|
||||
if (bestStation == -1)
|
||||
{
|
||||
if (!accesspoint)
|
||||
{
|
||||
#if defined(WIFI_AP_ENABLE)
|
||||
Serial.println("No known networks found, entering AccessPoint fallback mode");
|
||||
accesspoint = true;
|
||||
#else
|
||||
Serial.println("No known networks found");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("AccessPoint mode selected in config");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.printf("Connecting to Wifi Network: %s\n", stationList[bestStation].ssid);
|
||||
if (stationList[bestStation].dhcp == false)
|
||||
{
|
||||
#if defined(ST_IP)
|
||||
Serial.println("Applying static IP settings");
|
||||
#if !defined(ST_GATEWAY) || !defined(ST_NETMASK)
|
||||
#error "You must supply both Gateway and NetMask when specifying a static IP address"
|
||||
#endif
|
||||
IPAddress staticIP(ST_IP);
|
||||
IPAddress gateway(ST_GATEWAY);
|
||||
IPAddress subnet(ST_NETMASK);
|
||||
#if !defined(ST_DNS1)
|
||||
WiFi.config(staticIP, gateway, subnet);
|
||||
#else
|
||||
IPAddress dns1(ST_DNS1);
|
||||
#if !defined(ST_DNS2)
|
||||
WiFi.config(staticIP, gateway, subnet, dns1);
|
||||
#else
|
||||
IPAddress dns2(ST_DNS2);
|
||||
WiFi.config(staticIP, gateway, subnet, dns1, dns2);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
Serial.println("Static IP settings requested but not defined in config, falling back to dhcp");
|
||||
#endif
|
||||
}
|
||||
// Initiate network connection request
|
||||
WiFi.begin(stationList[bestStation].ssid, stationList[bestStation].password);
|
||||
|
||||
// Wait to connect, or timeout
|
||||
unsigned long start = millis();
|
||||
while ((millis() - start <= WIFI_WATCHDOG) && (WiFi.status() != WL_CONNECTED))
|
||||
{
|
||||
delay(500);
|
||||
Serial.print('.');
|
||||
}
|
||||
// If we have connected, inform user
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
{
|
||||
Serial.println("Client connection succeeded");
|
||||
accesspoint = false;
|
||||
// Note IP details
|
||||
ip = WiFi.localIP();
|
||||
net = WiFi.subnetMask();
|
||||
gw = WiFi.gatewayIP();
|
||||
Serial.printf("IP address: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
Serial.printf("Netmask : %d.%d.%d.%d\n", net[0], net[1], net[2], net[3]);
|
||||
Serial.printf("Gateway : %d.%d.%d.%d\n", gw[0], gw[1], gw[2], gw[3]);
|
||||
// Flash the LED to show we are connected
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
flashLED(50);
|
||||
delay(150);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Client connection Failed");
|
||||
WiFi.disconnect(); // (resets the WiFi scan)
|
||||
}
|
||||
}
|
||||
|
||||
if (accesspoint && (WiFi.status() != WL_CONNECTED))
|
||||
{
|
||||
// The accesspoint has been enabled, and we have not connected to any existing networks
|
||||
#if defined(AP_CHAN)
|
||||
Serial.println("Setting up Fixed Channel AccessPoint");
|
||||
Serial.print(" SSID : ");
|
||||
Serial.println(stationList[0].ssid);
|
||||
Serial.print(" Password : ");
|
||||
Serial.println(stationList[0].password);
|
||||
Serial.print(" Channel : ");
|
||||
Serial.println(AP_CHAN);
|
||||
WiFi.softAP(stationList[0].ssid, stationList[0].password, AP_CHAN);
|
||||
#else
|
||||
Serial.println("Setting up AccessPoint");
|
||||
Serial.print(" SSID : ");
|
||||
Serial.println(stationList[0].ssid);
|
||||
Serial.print(" Password : ");
|
||||
Serial.println(stationList[0].password);
|
||||
WiFi.softAP(stationList[0].ssid, stationList[0].password);
|
||||
#endif
|
||||
#if defined(AP_ADDRESS)
|
||||
// User has specified the AP details; apply them after a short delay
|
||||
// (https://github.com/espressif/arduino-esp32/issues/985#issuecomment-359157428)
|
||||
delay(100);
|
||||
IPAddress local_IP(AP_ADDRESS);
|
||||
IPAddress gateway(AP_ADDRESS);
|
||||
IPAddress subnet(255, 255, 255, 0);
|
||||
WiFi.softAPConfig(local_IP, gateway, subnet);
|
||||
#endif
|
||||
// Note AP details
|
||||
ip = WiFi.softAPIP();
|
||||
net = WiFi.subnetMask();
|
||||
gw = WiFi.gatewayIP();
|
||||
strcpy(apName, stationList[0].ssid);
|
||||
Serial.printf("IP address: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
|
||||
// Flash the LED to show we are connected
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
flashLED(150);
|
||||
delay(50);
|
||||
}
|
||||
// Start the DNS captive portal if requested
|
||||
if (stationList[0].dhcp == true)
|
||||
{
|
||||
Serial.println("Starting Captive Portal");
|
||||
dnsServer.start(DNS_PORT, "*", ip);
|
||||
captivePortal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
|
@ -375,18 +123,17 @@ void setup()
|
|||
Serial.println();
|
||||
Serial.println("====");
|
||||
Serial.print("esp32-cam-webserver: ");
|
||||
Serial.println(myName);
|
||||
Serial.println(camera_name);
|
||||
Serial.print("Code Built: ");
|
||||
Serial.println(myVer);
|
||||
Serial.print("Base Release: ");
|
||||
Serial.println(baseVersion);
|
||||
|
||||
if (stationCount == 0)
|
||||
startWiFi();
|
||||
|
||||
while (!WiFi.isConnected())
|
||||
{
|
||||
Serial.println("\nFatal Error; Halting");
|
||||
Serial.println("No wifi ssid details have been configured; we cannot connect to WiFi or start our own AccessPoint");
|
||||
while (true)
|
||||
delay(1000);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
#if defined(LED_PIN) // If we have a notification LED, set it to output
|
||||
|
@ -445,7 +192,7 @@ void setup()
|
|||
{
|
||||
delay(100); // need a delay here or the next serial o/p gets missed
|
||||
Serial.println("Halted: Camera sensor failed to initialise");
|
||||
Serial.println("Will reboot to try again in 10s\n");
|
||||
Serial.println("Will reboot to try again in 10s\r\n");
|
||||
delay(10000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
@ -480,23 +227,23 @@ void setup()
|
|||
|
||||
// M5 Stack Wide has special needs
|
||||
#if defined(CAMERA_MODEL_M5STACK_WIDE)
|
||||
s->set_vflip(s, 1);
|
||||
s->set_hmirror(s, 1);
|
||||
espCamSensor->set_vflip(espCamSensor, 1);
|
||||
espCamSensor->set_hmirror(espCamSensor, 1);
|
||||
#endif
|
||||
|
||||
// Config can override mirror and flip
|
||||
#if defined(H_MIRROR)
|
||||
s->set_hmirror(s, H_MIRROR);
|
||||
espCamSensor->set_hmirror(espCamSensor, H_MIRROR);
|
||||
#endif
|
||||
#if defined(V_FLIP)
|
||||
s->set_vflip(s, V_FLIP);
|
||||
sespCamSensor->set_vflip(espCamSensor, V_FLIP);
|
||||
#endif
|
||||
|
||||
// set initial frame rate
|
||||
#if defined(DEFAULT_RESOLUTION)
|
||||
espCamSensor->set_framesize(espCamSensor, DEFAULT_RESOLUTION);
|
||||
#else
|
||||
s->set_framesize(s, FRAMESIZE_SVGA);
|
||||
espCamSensor->set_framesize(espCamSensor, FRAMESIZE_SVGA);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -507,34 +254,6 @@ void setup()
|
|||
* https://github.com/espressif/esp32-camera/blob/master/driver/include/sensor.h#L149
|
||||
*/
|
||||
|
||||
//s->set_framesize(s, FRAMESIZE_SVGA); // FRAMESIZE_[QQVGA|HQVGA|QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA|QXGA(ov3660)]);
|
||||
//s->set_quality(s, val); // 10 to 63
|
||||
//s->set_brightness(s, 0); // -2 to 2
|
||||
//s->set_contrast(s, 0); // -2 to 2
|
||||
//s->set_saturation(s, 0); // -2 to 2
|
||||
//s->set_special_effect(s, 0); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, 4 - Green Tint, 5 - Blue Tint, 6 - Sepia)
|
||||
//s->set_whitebal(s, 1); // aka 'awb' in the UI; 0 = disable , 1 = enable
|
||||
//s->set_awb_gain(s, 1); // 0 = disable , 1 = enable
|
||||
//s->set_wb_mode(s, 0); // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
|
||||
//s->set_exposure_ctrl(s, 1); // 0 = disable , 1 = enable
|
||||
//s->set_aec2(s, 0); // 0 = disable , 1 = enable
|
||||
//s->set_ae_level(s, 0); // -2 to 2
|
||||
//s->set_aec_value(s, 300); // 0 to 1200
|
||||
//s->set_gain_ctrl(s, 1); // 0 = disable , 1 = enable
|
||||
//s->set_agc_gain(s, 0); // 0 to 30
|
||||
//s->set_gainceiling(s, (gainceiling_t)0); // 0 to 6
|
||||
//s->set_bpc(s, 0); // 0 = disable , 1 = enable
|
||||
//s->set_wpc(s, 1); // 0 = disable , 1 = enable
|
||||
//s->set_raw_gma(s, 1); // 0 = disable , 1 = enable
|
||||
//s->set_lenc(s, 1); // 0 = disable , 1 = enable
|
||||
//s->set_hmirror(s, 0); // 0 = disable , 1 = enable
|
||||
//s->set_vflip(s, 0); // 0 = disable , 1 = enable
|
||||
//s->set_dcw(s, 1); // 0 = disable , 1 = enable
|
||||
//s->set_colorbar(s, 0); // 0 = disable , 1 = enable
|
||||
|
||||
// We now have camera with default init
|
||||
// check for saved preferences and apply them
|
||||
|
||||
if (filesystem)
|
||||
{
|
||||
filesystemStart();
|
||||
|
@ -543,13 +262,9 @@ void setup()
|
|||
}
|
||||
else
|
||||
{
|
||||
Serial.println("No Internal Filesystem, cannot save preferences or face DB");
|
||||
Serial.println("No Internal Filesystem, cannot save preferences");
|
||||
}
|
||||
|
||||
/*
|
||||
* Camera setup complete; initialise the rest of the hardware.
|
||||
*/
|
||||
|
||||
// Initialise and set the lamp
|
||||
if (lampVal != -1)
|
||||
{
|
||||
|
@ -562,34 +277,17 @@ void setup()
|
|||
Serial.println("No lamp, or lamp disabled in config");
|
||||
}
|
||||
|
||||
// Having got this far; start Wifi and loop until we are connected or have started an AccessPoint
|
||||
while ((WiFi.status() != WL_CONNECTED) && !accesspoint)
|
||||
{
|
||||
WifiSetup();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// Now we have a network we can start the two http handlers for the UI and Stream.
|
||||
startCameraServer();
|
||||
startStreamServer();
|
||||
|
||||
// Construct the app and stream URLs
|
||||
sprintf(httpURL, "http://%d.%d.%d.%d:%d/", ip[0], ip[1], ip[2], ip[3], HTTP_PORT);
|
||||
|
||||
Serial.printf("\nCamera Ready!\nUse '%s' to connect\n", httpURL);
|
||||
|
||||
if (debugData)
|
||||
Serial.println("Camera debug data is enabled (send any char to disable)");
|
||||
else
|
||||
Serial.println("Camera debug data is disabled (send any char to enable)");
|
||||
Serial.printf("\r\nCamera Ready!\r\nUse '%s' to connect\r\n", httpURL);
|
||||
|
||||
/*
|
||||
* Main camera streams running, now enable MQTT
|
||||
* */
|
||||
|
||||
#if defined(MQTT_HOST)
|
||||
startMQTTClient(MQTT_HOST, MQTT_PORT, MQTT_TOPIC, myName, MQTT_CERT);
|
||||
#endif
|
||||
startMQTTClient();
|
||||
|
||||
// Used when dumping status; these are slow functions, so just do them once during startup
|
||||
sketchSize = ESP.getSketchSize();
|
||||
|
@ -604,19 +302,6 @@ void loop()
|
|||
* The stream and URI handler processes initiated by the startCameraServer() call at the
|
||||
* end of setup() will handle the camera and UI processing from now on.
|
||||
*/
|
||||
if (accesspoint)
|
||||
{
|
||||
// Accespoint is permanently up, so just loop, servicing the captive portal as needed
|
||||
unsigned long start = millis();
|
||||
while (millis() - start < WIFI_WATCHDOG)
|
||||
{
|
||||
delay(100);
|
||||
if (captivePortal)
|
||||
dnsServer.processNextRequest();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// client mode can fail; so reconnect as appropriate
|
||||
static bool warned = false;
|
||||
if (WiFi.status() == WL_CONNECTED)
|
||||
|
@ -628,28 +313,7 @@ void loop()
|
|||
Serial.println("WiFi reconnected");
|
||||
warned = false;
|
||||
}
|
||||
// loop here for WIFI_WATCHDOG, turning debugData true/false depending on serial input..
|
||||
unsigned long start = millis();
|
||||
while (millis() - start < WIFI_WATCHDOG)
|
||||
{
|
||||
delay(100);
|
||||
if (Serial.available())
|
||||
{
|
||||
// Toggle debug output on serial input
|
||||
if (debugData)
|
||||
{
|
||||
debugData = false;
|
||||
Serial.println("Camera debug data is disabled (send any char to enable)");
|
||||
}
|
||||
else
|
||||
{
|
||||
debugData = true;
|
||||
Serial.println("Camera debug data is enabled (send any char to disable)");
|
||||
}
|
||||
}
|
||||
while (Serial.available())
|
||||
Serial.read(); // chomp the buffer
|
||||
}
|
||||
handleMQTT();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -661,7 +325,6 @@ void loop()
|
|||
Serial.println("WiFi disconnected, retrying");
|
||||
warned = true;
|
||||
}
|
||||
WifiSetup();
|
||||
}
|
||||
startWiFi();
|
||||
}
|
||||
}
|
||||
|
|
197
mqtt_client.cpp
197
mqtt_client.cpp
|
@ -1,119 +1,105 @@
|
|||
#include "Arduino.h"
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include "PubSubClient.h"
|
||||
#include <Preferences.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <cstring>
|
||||
#include "myconfig.h"
|
||||
#include <string.h>
|
||||
|
||||
extern UBaseType_t activeClients;
|
||||
extern int mqtt_port;
|
||||
extern bool updating;
|
||||
|
||||
char KEY_CAM_NAME[] = "cam_name";
|
||||
char KEY_MMQT_HOST[] = "mmqt_host";
|
||||
char KEY_MMQT_PORT[] = "mmqt_port";
|
||||
char KEY_MMQT_USER[] = "mmqt_user";
|
||||
char KEY_MMQT_PASS[] = "mmqt_pass";
|
||||
char KEY_MMQT_TOPIC[] = "mmqt_topic";
|
||||
char KEY_MMQT_CERT[] = "mmqt_cert";
|
||||
|
||||
char camera_name[64];
|
||||
char client_id[64];
|
||||
char mqtt_topic[64];
|
||||
const unsigned long publishPeriod = 60000;
|
||||
unsigned long lastMQTTPublish = 0;
|
||||
|
||||
const static char *MQTT_JSON = "{ \
|
||||
\"ClientId\":\"%s\", \
|
||||
\"CameraName\":\"%s\", \
|
||||
\"Millis\":\"%lu\", \
|
||||
\"ActiveClients\":%d \
|
||||
}";
|
||||
|
||||
WiFiClient wifiClient;
|
||||
PubSubClient mqttClient(wifiClient);
|
||||
uint16_t mqtt_port = 1883;
|
||||
char *mqtt_host = new char[64];
|
||||
char *mqtt_pub_topic = new char[256];
|
||||
char *mqtt_client_id = new char[64];
|
||||
const char *MQTT_JSON = "{\"ClientId\":\"%s\",\"ActiveClients\":%d}";
|
||||
|
||||
void startMQTTClient(char *host, char *topic, char *cert);
|
||||
void mqttconnect();
|
||||
void mqttCB(void *pvParameters);
|
||||
|
||||
TaskHandle_t tMQTT; // handles client connection to the MQTT Server
|
||||
void mqttCB(void *pvParameters)
|
||||
{
|
||||
TickType_t xLastWakeTime = xTaskGetTickCount();
|
||||
TickType_t xFrequency = pdMS_TO_TICKS(60000); //Every minute
|
||||
|
||||
while (true)
|
||||
{
|
||||
/* if client was disconnected then try to reconnect again */
|
||||
if (!mqttClient.connected())
|
||||
{
|
||||
mqttconnect();
|
||||
}
|
||||
|
||||
Serial.printf("ActiveClients %d\n", activeClients);
|
||||
|
||||
char msg[64] = "";
|
||||
snprintf(msg, 64, MQTT_JSON, mqtt_client_id, activeClients);
|
||||
Serial.printf("Publishing message %s\n", msg);
|
||||
/* publish the message */
|
||||
mqttClient.publish(mqtt_pub_topic, msg);
|
||||
|
||||
// Let other tasks run after serving every client
|
||||
taskYIELD();
|
||||
vTaskDelayUntil(&xLastWakeTime, xFrequency);
|
||||
}
|
||||
}
|
||||
void startMQTTClient(char *host, char *topic, char *cert);
|
||||
|
||||
void mqttconnect()
|
||||
{
|
||||
u32_t defaultIp = 0;
|
||||
IPAddress noConnIP = IPAddress(defaultIp);
|
||||
IPAddress serverIp = IPAddress(defaultIp);
|
||||
unsigned long period = 5000;
|
||||
unsigned long lastRun = 0;
|
||||
|
||||
/* Loop until reconnected */
|
||||
while (!mqttClient.connected())
|
||||
{
|
||||
Preferences preferences;
|
||||
preferences.begin("ESP32-CAM", true);
|
||||
|
||||
if (millis() - lastRun < period)
|
||||
String tmp_camera_name = preferences.getString(KEY_CAM_NAME, "Camera Name");
|
||||
String tmp_mqtt_topic = preferences.getString(KEY_MMQT_TOPIC, "default/topic");
|
||||
int mqtt_port = preferences.getInt(KEY_MMQT_PORT, 1883);
|
||||
String mqtt_host = preferences.getString(KEY_MMQT_HOST, "");
|
||||
String mqtt_user = preferences.getString(KEY_MMQT_USER, "");
|
||||
String mqtt_pass = preferences.getString(KEY_MMQT_PASS, "");
|
||||
String mqtt_cert = preferences.getString(KEY_MMQT_CERT, "");
|
||||
|
||||
preferences.end();
|
||||
|
||||
if (mqtt_host == "" || mqtt_pass == "" || mqtt_user == "")
|
||||
{
|
||||
yield();
|
||||
continue;
|
||||
Serial.printf("Couldn't establish MQTT Connection: %s, %s, %s", mqtt_host.c_str(), mqtt_user.c_str(), mqtt_pass.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
lastRun = millis();
|
||||
sprintf(camera_name, "%s", tmp_camera_name.c_str());
|
||||
sprintf(mqtt_topic, "%s", tmp_mqtt_topic.c_str());
|
||||
|
||||
/* Configure the MQTT server with IPaddress and port. */
|
||||
while (noConnIP == serverIp)
|
||||
{
|
||||
Serial.printf("Querying '%s:%d'...\n", mqtt_host, mqtt_port);
|
||||
Serial.printf("Querying '%s:%d'...\r\n", mqtt_host.c_str(), mqtt_port);
|
||||
|
||||
serverIp = MDNS.queryHost(mqtt_host);
|
||||
IPAddress serverIp = MDNS.queryHost(mqtt_host);
|
||||
|
||||
Serial.printf("IP address of server: %s\n", serverIp.toString().c_str());
|
||||
|
||||
if (noConnIP == serverIp)
|
||||
{
|
||||
WiFi.hostByName(mqtt_host, serverIp);
|
||||
Serial.printf("IP address of server: %s\n", serverIp.toString().c_str());
|
||||
if ((uint32_t)serverIp == 0)
|
||||
{
|
||||
serverIp = noConnIP;
|
||||
}
|
||||
WiFi.hostByName(mqtt_host.c_str(), serverIp);
|
||||
}
|
||||
|
||||
if (noConnIP != serverIp)
|
||||
if ((uint32_t)serverIp == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
yield();
|
||||
return;
|
||||
}
|
||||
|
||||
mqttClient.setServer(serverIp, mqtt_port);
|
||||
Serial.printf("IP address of MQTT server: %s\r\n", serverIp.toString().c_str());
|
||||
|
||||
/* connect now */
|
||||
char clientId[100] = {};
|
||||
tmp_camera_name.toUpperCase();
|
||||
char random[32] = {'-'};
|
||||
|
||||
srand((unsigned int)(time(NULL)));
|
||||
int index = 0;
|
||||
|
||||
char char1[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (index = 1; index < 31; index++)
|
||||
char char1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
for (int index = 1; index < 31; index++)
|
||||
{
|
||||
random[index] = char1[rand() % (sizeof char1 - 1)];
|
||||
}
|
||||
Serial.println(random);
|
||||
sprintf(clientId, "%s", mqtt_client_id);
|
||||
strcat(clientId, random);
|
||||
sprintf(client_id, "%s%s", tmp_camera_name.c_str(), random);
|
||||
|
||||
Serial.printf("MQTT connecting as '%s'...\n", clientId);
|
||||
if (mqttClient.connect(clientId, "testUser", "1234")) //, "security/healthcheck", 20, true, "WillMessage", true))
|
||||
/* connect now */
|
||||
Serial.printf("MQTT connecting as '%s' (%s:%s)...\r\n", client_id, mqtt_host.c_str(), mqtt_pass.c_str());
|
||||
try
|
||||
{
|
||||
Serial.println("connected");
|
||||
|
||||
mqttClient.setServer(serverIp, mqtt_port);
|
||||
|
||||
if (mqttClient.connect(client_id, mqtt_user.c_str(), mqtt_pass.c_str()))
|
||||
{
|
||||
Serial.printf("MQTT Connected to '%s'\r\n", mqtt_host.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -123,27 +109,52 @@ void mqttconnect()
|
|||
Serial.printf("try again in %d seconds/n", 5);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{ // reference to the base of a polymorphic object
|
||||
Serial.println(e.what()); // information from length_error printed
|
||||
}
|
||||
}
|
||||
|
||||
void startMQTTClient(const char *host, int port, const char *topic, const char *client_id, const void *cert)
|
||||
void handleMQTT()
|
||||
{
|
||||
mqtt_port = port;
|
||||
strcpy(mqtt_pub_topic, topic);
|
||||
strcpy(mqtt_host, host);
|
||||
strcpy(mqtt_client_id, client_id);
|
||||
|
||||
Serial.printf("Starting MQTT Client '%s'\n", client_id);
|
||||
if (updating)
|
||||
{
|
||||
Serial.println("Updating, killing MQTT Server");
|
||||
mqttClient.disconnect();
|
||||
}
|
||||
|
||||
mqttClient.loop();
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
if (lastMQTTPublish == 0 || ((now - lastMQTTPublish) >= publishPeriod))
|
||||
{
|
||||
/* if client was disconnected then try to reconnect again */
|
||||
if (!mqttClient.connected())
|
||||
{
|
||||
mqttconnect();
|
||||
}
|
||||
|
||||
lastMQTTPublish = now;
|
||||
|
||||
char msg[128] = "";
|
||||
snprintf(msg, 128, MQTT_JSON, client_id, camera_name, lastMQTTPublish, activeClients);
|
||||
Serial.printf("Publishing message %s\r\n", msg);
|
||||
/* publish the message */
|
||||
mqttClient.publish(mqtt_topic, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void startMQTTClient()
|
||||
{
|
||||
Serial.printf("Starting MQTT Client '%s'\r\n", camera_name);
|
||||
|
||||
/* Set SSL/TLS certificate */
|
||||
// wifiClient.setCACert(ca_cert);
|
||||
|
||||
/* Start main task. */
|
||||
xTaskCreatePinnedToCore(
|
||||
mqttCB,
|
||||
"mqtt",
|
||||
4096,
|
||||
NULL,
|
||||
2,
|
||||
&tMQTT,
|
||||
1);
|
||||
if (!mqttClient.connected())
|
||||
{
|
||||
mqttconnect();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,4 +19,9 @@ monitor_speed = 115200
|
|||
build_flags =
|
||||
-DBOARD_HAS_PSRAM
|
||||
-mfix-esp32-psram-cache-issue
|
||||
lib_deps = knolleary/PubSubClient@^2.8
|
||||
lib_deps =
|
||||
knolleary/PubSubClient@^2.8
|
||||
https://github.com/tzapu/WiFiManager.git#development
|
||||
ottowinter/ESPAsyncWebServer-esphome@^1.2.7
|
||||
me-no-dev/ESPAsyncTCP@^1.2.2
|
||||
Micro-RTSP@>=0.1.6
|
|
@ -0,0 +1,53 @@
|
|||
#include<Arduino.h>
|
||||
|
||||
String firmware_style_css =
|
||||
"<style>#file-input,input{width:100%;height:44px;border-radius:4px;margin:10px auto;font-size:15px}"
|
||||
"input{background:#f1f1f1;border:0;padding:0 15px}body{background:#3498db;font-family:sans-serif;font-size:14px;color:#777}"
|
||||
"#file-input{padding:0;border:1px solid #ddd;line-height:44px;text-align:left;display:block;cursor:pointer}"
|
||||
"#bar,#prgbar{background-color:#f1f1f1;border-radius:10px}#bar{background-color:#3498db;width:0%;height:10px}"
|
||||
"form{background:#fff;max-width:258px;margin:75px auto;padding:30px;border-radius:5px;text-align:center}"
|
||||
".btn{background:#3498db;color:#fff;cursor:pointer}</style>";
|
||||
|
||||
String firmware_html =
|
||||
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
|
||||
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
|
||||
"<input type='file' name='update' id='file' onchange='sub(this)' style=display:none>"
|
||||
"<label id='file-input' for='file'> Choose file...</label>"
|
||||
"<input type='submit' class=btn value='Update'>"
|
||||
"<br><br>"
|
||||
"<div id='prg'></div>"
|
||||
"<br><div id='prgbar'><div id='bar'></div></div><br></form>"
|
||||
"<script>"
|
||||
"function sub(obj){"
|
||||
"var fileName = obj.value.split('\\\\');"
|
||||
"document.getElementById('file-input').innerHTML = ' '+ fileName[fileName.length-1];"
|
||||
"};"
|
||||
"$('form').submit(function(e){"
|
||||
"e.preventDefault();"
|
||||
"var form = $('#upload_form')[0];"
|
||||
"var data = new FormData(form);"
|
||||
"$.ajax({"
|
||||
"url: '/doUpdate',"
|
||||
"type: 'POST',"
|
||||
"data: data,"
|
||||
"contentType: false,"
|
||||
"processData:false,"
|
||||
"xhr: function() {"
|
||||
"var xhr = new window.XMLHttpRequest();"
|
||||
"xhr.upload.addEventListener('progress', function(evt) {"
|
||||
"if (evt.lengthComputable) {"
|
||||
"var per = evt.loaded / evt.total;"
|
||||
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
|
||||
"$('#bar').css('width',Math.round(per*100) + '%');"
|
||||
"}"
|
||||
"}, false);"
|
||||
"return xhr;"
|
||||
"},"
|
||||
"success:function(d, s) {"
|
||||
"console.log('success!') "
|
||||
"},"
|
||||
"error: function (a, b, c) {"
|
||||
"}"
|
||||
"});"
|
||||
"});"
|
||||
"</script>" + firmware_style_css;
|
|
@ -252,6 +252,11 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
|
|||
<button id="save_prefs" title="Save Preferences on camera module">Save</button>
|
||||
<button id="clear_prefs" title="Erase saved Preferences on camera module">Erase</button>
|
||||
</div>
|
||||
<div class="input-group" id="esp32-group">
|
||||
<label for="clear_wifi" style="line-height: 2em;">Config</label>
|
||||
<button id="clear_wifi" title="Clear the WiFi config">Clear WiFi Config</button>
|
||||
<button id="firmware" title="Update module firmware">Update Firmware</button>
|
||||
</div>
|
||||
<div class="input-group" id="cam_name-group">
|
||||
<label for="cam_name">
|
||||
<a href="/dump" title="System Info" target="_blank">Name</a></label>
|
||||
|
@ -303,11 +308,11 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
|
|||
const recognize = document.getElementById('face_recognize')
|
||||
const framesize = document.getElementById('framesize')
|
||||
const swapButton = document.getElementById('swap-viewer')
|
||||
// const saveFaceButton = document.getElementById('save_face')
|
||||
// const clearFaceButton = document.getElementById('clear_face')
|
||||
const savePrefsButton = document.getElementById('save_prefs')
|
||||
const clearPrefsButton = document.getElementById('clear_prefs')
|
||||
const rebootButton = document.getElementById('reboot')
|
||||
const clearWifiButton = document.getElementById('clear_wifi')
|
||||
const firmwareButton = document.getElementById('firmware')
|
||||
|
||||
const hide = el => {
|
||||
el.classList.add('hidden')
|
||||
|
@ -593,18 +598,6 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
|
|||
window.open('/?view=simple','_self');
|
||||
}
|
||||
|
||||
// saveFaceButton.onclick = () => {
|
||||
// if (confirm("Saving the current face database?")) {
|
||||
// updateConfig(saveFaceButton);
|
||||
// }
|
||||
// }
|
||||
|
||||
// clearFaceButton.onclick = () => {
|
||||
// if (confirm("Removing the face database?")) {
|
||||
// updateConfig(clearFaceButton);
|
||||
// }
|
||||
// }
|
||||
|
||||
savePrefsButton.onclick = () => {
|
||||
if (confirm("Save the current preferences?")) {
|
||||
updateConfig(savePrefsButton);
|
||||
|
@ -625,8 +618,19 @@ const uint8_t index_ov2640_html[] = R"=====(<!doctype html>
|
|||
}
|
||||
}
|
||||
|
||||
clearWifiButton.onclick = () => {
|
||||
if (confirm("Clear the Wifi Config?")) {
|
||||
updateConfig(clearWifiButton);
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
firmwareButton.onclick = () => {
|
||||
window.open('/firmware','_self');
|
||||
}
|
||||
|
||||
})
|
||||
</script>
|
||||
</html>)=====";
|
||||
|
||||
size_t index_ov2640_html_len = sizeof(index_ov2640_html)-1;
|
||||
size_t index_ov2640_html_len = sizeof(index_ov2640_html) - 1;
|
20
storage.cpp
20
storage.cpp
|
@ -6,15 +6,13 @@
|
|||
extern void flashLED(int flashtime);
|
||||
extern int myRotation; // Rotation
|
||||
extern int lampVal; // The current Lamp value
|
||||
extern int8_t detection_enabled; // Face detection enable
|
||||
extern int8_t recognition_enabled; // Face recognition enable
|
||||
|
||||
/*
|
||||
* Useful utility when debugging...
|
||||
*/
|
||||
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
|
||||
Serial.printf("Listing SPIFFS directory: %s\n", dirname);
|
||||
Serial.printf("Listing SPIFFS directory: %s\r\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if(!root){
|
||||
|
@ -52,7 +50,7 @@ void dumpPrefs(fs::FS &fs){
|
|||
Serial.println("");
|
||||
file.close();
|
||||
} else {
|
||||
Serial.printf("%s not found, nothing to dump.\n", PREFERENCES_FILE);
|
||||
Serial.printf("%s not found, nothing to dump.\r\n", PREFERENCES_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +58,7 @@ void loadPrefs(fs::FS &fs){
|
|||
if (fs.exists(PREFERENCES_FILE)) {
|
||||
// read file into a string
|
||||
String prefs;
|
||||
Serial.printf("Loading preferences from file %s\n", PREFERENCES_FILE);
|
||||
Serial.printf("Loading preferences from file %s\r\n", PREFERENCES_FILE);
|
||||
File file = fs.open(PREFERENCES_FILE, FILE_READ);
|
||||
if (!file) {
|
||||
Serial.println("Failed to open preferences file");
|
||||
|
@ -100,22 +98,20 @@ void loadPrefs(fs::FS &fs){
|
|||
s->set_hmirror(s, jsonExtract(prefs, "hmirror").toInt());
|
||||
s->set_dcw(s, jsonExtract(prefs, "dcw").toInt());
|
||||
s->set_colorbar(s, jsonExtract(prefs, "colorbar").toInt());
|
||||
detection_enabled = jsonExtract(prefs, "face_detect").toInt();
|
||||
recognition_enabled = jsonExtract(prefs, "face_recognize").toInt();
|
||||
myRotation = jsonExtract(prefs, "rotate").toInt();
|
||||
// close the file
|
||||
file.close();
|
||||
dumpPrefs(SPIFFS);
|
||||
} else {
|
||||
Serial.printf("Preference file %s not found; using system defaults.\n", PREFERENCES_FILE);
|
||||
Serial.printf("Preference file %s not found; using system defaults.\r\n", PREFERENCES_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
void savePrefs(fs::FS &fs){
|
||||
if (fs.exists(PREFERENCES_FILE)) {
|
||||
Serial.printf("Updating %s\n", PREFERENCES_FILE);
|
||||
Serial.printf("Updating %s\r\n", PREFERENCES_FILE);
|
||||
} else {
|
||||
Serial.printf("Creating %s\n", PREFERENCES_FILE);
|
||||
Serial.printf("Creating %s\r\n", PREFERENCES_FILE);
|
||||
}
|
||||
File file = fs.open(PREFERENCES_FILE, FILE_WRITE);
|
||||
static char json_response[1024];
|
||||
|
@ -147,8 +143,6 @@ void savePrefs(fs::FS &fs){
|
|||
p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
|
||||
p+=sprintf(p, "\"dcw\":%u,", s->status.dcw);
|
||||
p+=sprintf(p, "\"colorbar\":%u,", s->status.colorbar);
|
||||
p+=sprintf(p, "\"face_detect\":%u,", detection_enabled);
|
||||
p+=sprintf(p, "\"face_recognize\":%u,", recognition_enabled);
|
||||
p+=sprintf(p, "\"rotate\":\"%d\"", myRotation);
|
||||
*p++ = '}';
|
||||
*p++ = 0;
|
||||
|
@ -159,7 +153,7 @@ void savePrefs(fs::FS &fs){
|
|||
|
||||
void removePrefs(fs::FS &fs) {
|
||||
if (fs.exists(PREFERENCES_FILE)) {
|
||||
Serial.printf("Removing %s\r\n", PREFERENCES_FILE);
|
||||
Serial.printf("Removing %s\r\r\n", PREFERENCES_FILE);
|
||||
if (!fs.remove(PREFERENCES_FILE)) {
|
||||
Serial.println("Error removing preferences");
|
||||
}
|
||||
|
|
|
@ -11,16 +11,12 @@
|
|||
#include <esp_wifi.h>
|
||||
#include <esp_sleep.h>
|
||||
#include <driver/rtc_io.h>
|
||||
|
||||
// Select camera model
|
||||
//#define CAMERA_MODEL_WROVER_KIT
|
||||
//#define CAMERA_MODEL_ESP_EYE
|
||||
//#define CAMERA_MODEL_M5STACK_PSRAM
|
||||
//#define CAMERA_MODEL_M5STACK_WIDE
|
||||
#define CAMERA_MODEL_AI_THINKER // default
|
||||
|
||||
#include "myconfig.h"
|
||||
#include "camera_pins.h"
|
||||
|
||||
extern IPAddress espIP;
|
||||
extern bool updating;
|
||||
|
||||
/*
|
||||
Next one is an include with wifi credentials.
|
||||
This is what you need to do:
|
||||
|
@ -39,6 +35,7 @@
|
|||
#endif
|
||||
int streamPort = STREAM_PORT;
|
||||
WebServer server(streamPort);
|
||||
char streamURL[64] = {"Undefined"};
|
||||
|
||||
// ===== rtos task handles =========================
|
||||
// Streaming is implemented with 3 tasks:
|
||||
|
@ -54,7 +51,7 @@ QueueHandle_t streamingClients;
|
|||
UBaseType_t activeClients;
|
||||
|
||||
// We will try to achieve 25 FPS frame rate
|
||||
const int FPS = 14;
|
||||
const int FPS = 10;
|
||||
|
||||
// We will handle web client requests every 50 ms (20 Hz)
|
||||
const int WSINTERVAL = 100;
|
||||
|
@ -67,8 +64,7 @@ void handleJPGSstream(void);
|
|||
void streamCB(void *pvParameters);
|
||||
void handleJPG(void);
|
||||
void handleNotFound();
|
||||
void startStreamServer(int sPort);
|
||||
|
||||
void startStreamServer();
|
||||
|
||||
// ==== Memory allocator that takes advantage of PSRAM if present =======================
|
||||
char *allocateMemory(char *aPtr, size_t aSize)
|
||||
|
@ -133,7 +129,7 @@ void mjpegCB(void *pvParameters)
|
|||
NULL, // parameters
|
||||
2, // priority
|
||||
&tCam, // RTOS task handle
|
||||
APP_CPU); // core
|
||||
tskNO_AFFINITY); // core
|
||||
|
||||
// Creating task to push the stream to all connected clients
|
||||
xTaskCreatePinnedToCore(
|
||||
|
@ -143,7 +139,7 @@ void mjpegCB(void *pvParameters)
|
|||
NULL, //(void*) handler,
|
||||
2,
|
||||
&tStream,
|
||||
APP_CPU);
|
||||
tskNO_AFFINITY);
|
||||
|
||||
// Registering webserver handling routines
|
||||
server.on("/mjpeg/1", HTTP_GET, handleJPGSstream);
|
||||
|
@ -427,7 +423,7 @@ void handleNotFound()
|
|||
void startStreamServer()
|
||||
{
|
||||
|
||||
Serial.printf("Starting web server on port: '%d'\n", streamPort);
|
||||
Serial.printf("Starting stream server on port: '%d'\n", streamPort);
|
||||
|
||||
// Start mainstreaming RTOS task
|
||||
xTaskCreatePinnedToCore(
|
||||
|
@ -437,5 +433,7 @@ void startStreamServer()
|
|||
NULL,
|
||||
2,
|
||||
&tMjpeg,
|
||||
APP_CPU);
|
||||
tskNO_AFFINITY);
|
||||
|
||||
sprintf(streamURL, "http://%d.%d.%d.%d:%d/mjpeg/1/", espIP[0], espIP[1], espIP[2], espIP[3], streamPort);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
#include <WiFiManager.h>
|
||||
#include <Preferences.h>
|
||||
#include <ESPmDNS.h>
|
||||
|
||||
extern void flashLED(int flashtime);
|
||||
|
||||
WiFiManager wifiManager;
|
||||
IPAddress espIP;
|
||||
IPAddress espSubnet;
|
||||
IPAddress espGateway;
|
||||
|
||||
extern char KEY_CAM_NAME[];
|
||||
extern char KEY_MMQT_HOST[];
|
||||
extern char KEY_MMQT_PORT[];
|
||||
extern char KEY_MMQT_USER[];
|
||||
extern char KEY_MMQT_PASS[];
|
||||
extern char KEY_MMQT_TOPIC[];
|
||||
extern char KEY_MMQT_CERT[];
|
||||
void resetWiFiConfig()
|
||||
{
|
||||
wifiManager.resetSettings();
|
||||
WiFi.disconnect(true);
|
||||
delay(2000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void configModeCallback(WiFiManager *myWiFiManager)
|
||||
{
|
||||
Serial.printf("Entered config mode. SSID '%s' AP: '%s'\r\n", myWiFiManager->getConfigPortalSSID().c_str(), WiFi.softAPIP().toString().c_str());
|
||||
}
|
||||
|
||||
//callback notifying us of the need to save config
|
||||
void saveConfigCallback()
|
||||
{
|
||||
Serial.println("Saving config");
|
||||
}
|
||||
|
||||
void startWiFi()
|
||||
{
|
||||
Serial.println("Starting WiFi");
|
||||
|
||||
// Feedback that we are now attempting to connect
|
||||
flashLED(300);
|
||||
delay(100);
|
||||
flashLED(300);
|
||||
|
||||
wifiManager.setAPCallback(configModeCallback);
|
||||
wifiManager.setSaveConfigCallback(saveConfigCallback);
|
||||
wifiManager.setConfigPortalTimeout(180);
|
||||
wifiManager.setConnectTimeout(30);
|
||||
wifiManager.setTimeout(30);
|
||||
|
||||
Preferences preferences;
|
||||
preferences.begin("ESP32-CAM", false);
|
||||
|
||||
String camera_name = preferences.getString(KEY_CAM_NAME, "ESP32-CAM");
|
||||
String mqtt_port = preferences.getString(KEY_MMQT_PORT, "1883");
|
||||
String mqtt_host = preferences.getString(KEY_MMQT_HOST, "");
|
||||
String mqtt_user = preferences.getString(KEY_MMQT_USER, "");
|
||||
String mqtt_pass = preferences.getString(KEY_MMQT_PASS, "");
|
||||
String mqtt_topic = preferences.getString(KEY_MMQT_TOPIC, "");
|
||||
String mqtt_cert = preferences.getString(KEY_MMQT_CERT, "");
|
||||
|
||||
WiFiManagerParameter camName(KEY_CAM_NAME, "Camera Name", camera_name.c_str(), 64);
|
||||
WiFiManagerParameter mqttHost(KEY_MMQT_HOST, "MQTT Host", mqtt_host.c_str(), 64);
|
||||
WiFiManagerParameter mqttPort(KEY_MMQT_PORT, "MQTT Port", mqtt_port.c_str(), 6);
|
||||
WiFiManagerParameter mqttUser(KEY_MMQT_USER, "MQTT User", mqtt_user.c_str(), 64);
|
||||
WiFiManagerParameter mqttPass(KEY_MMQT_PASS, "MQTT Password", mqtt_pass.c_str(), 256);
|
||||
WiFiManagerParameter mqttTopic(KEY_MMQT_TOPIC, "MQTT Publish Topic", mqtt_topic.c_str(), 256);
|
||||
WiFiManagerParameter mqttCert(KEY_MMQT_CERT, "MQTT Certificate", mqtt_cert.c_str(), 4096);
|
||||
|
||||
wifiManager.addParameter(&camName);
|
||||
wifiManager.addParameter(&mqttHost);
|
||||
wifiManager.addParameter(&mqttPort);
|
||||
wifiManager.addParameter(&mqttUser);
|
||||
wifiManager.addParameter(&mqttPass);
|
||||
wifiManager.addParameter(&mqttTopic);
|
||||
wifiManager.addParameter(&mqttCert);
|
||||
|
||||
wifiManager.setHostname(camera_name.c_str());
|
||||
if (!wifiManager.autoConnect(camera_name.c_str()))
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
espIP = WiFi.localIP();
|
||||
espSubnet = WiFi.subnetMask();
|
||||
espGateway = WiFi.gatewayIP();
|
||||
|
||||
preferences.putString(KEY_CAM_NAME, camName.getValue());
|
||||
preferences.putString(KEY_MMQT_PORT, mqttPort.getValue());
|
||||
preferences.putString(KEY_MMQT_HOST, mqttHost.getValue());
|
||||
preferences.putString(KEY_MMQT_USER, mqttUser.getValue());
|
||||
preferences.putString(KEY_MMQT_PASS, mqttPass.getValue());
|
||||
preferences.putString(KEY_MMQT_TOPIC, mqttTopic.getValue());
|
||||
preferences.putString(KEY_MMQT_CERT, mqttCert.getValue());
|
||||
|
||||
preferences.end();
|
||||
|
||||
Serial.printf("Host: '%s'\r\nUser: '%s'\r\nPass: '%s'\r\nTopic: '%s'\r\nCert: '%s'\r\n",
|
||||
preferences.getString("mqttHost", "").c_str(),
|
||||
preferences.getString("mqtt_user", "").c_str(),
|
||||
preferences.getString("mqttPass", "").c_str(),
|
||||
preferences.getString("mqttTopic", "").c_str(),
|
||||
preferences.getString("mqttCert", "").c_str());
|
||||
|
||||
if (!MDNS.begin(camera_name.c_str()))
|
||||
{
|
||||
Serial.println("Error setting up MDNS responder!");
|
||||
}
|
||||
Serial.println("mDNS responder started");
|
||||
|
||||
delay(500);
|
||||
|
||||
Serial.println("Wifi Started");
|
||||
}
|
Loading…
Reference in New Issue