All functioning...except OTA...

This commit is contained in:
Sam 2020-10-31 18:24:05 -05:00
parent 79c9c5b623
commit 5c5a04d55d
12 changed files with 707 additions and 995 deletions

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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

53
src/html/firmware.h Normal file
View File

@ -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;

View File

@ -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;

View File

@ -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");
}

View File

@ -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);
}

116
wifi_manager.cpp Normal file
View File

@ -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");
}