一、实际效果
该demo演示的在基于广域网使用APP实现远程实时查看ESP32-CAM所拍摄的视频流
二、准备工作
1.ESP32-CAM开发板 样品链接
2.USB TO TTL和杜邦线
4.安卓APP----链接:https://pan.baidu.com/s/1ZxIVD3EKzHdn6UchkXcnrw
提取码:n6tp
三、开发环境搭建
3.1 获取SDK
获取ESP32 SDK esp-idf,版本为v4.0
git clone -b release/v4.0 --recurse-submodules https://github.com/espressif/esp-idf
设置 IDF_PATH 路径
vim ~/.bashrc
之后按下 i 嵌入代码,任意一处添加路径,以我的路径为例
export IDF_PATH=/mnt/hgfs/share/Ai-Thinker-Open_ESP32-CAMERA_LAN/esp-idf
按下esc 再 :wq 表示写入保存
更新一下路径:
source ~/.bashrc
IDF_PATH 路径测试是否设置成功: echo $IDF_PATH
除了 ESP-IDF 本身,您还需要安装 ESP-IDF 使用的各种工具,比如编译器、调试器、Python 包等!
cd /mnt/hgfs/share/esp-idf //以我的路径为例
sudo ./install.sh
出现这个 , 表示 安装成功
此时,您刚刚安装的工具尚未添加至 PATH 环境变量,无法通过“命令窗口”使用这些工具。因此,必须设置一些环境变量,这可以通过 ESP-IDF 提供的另一个脚本完成。
注意下面命令2个小数点中间有一个空格!
. ./export.sh
成功后,便这样提示:
获取广域网CAM SDK
cd esp-idf
git clone --recurse-submodules https://github.com/Ai-Thinker-Open/Ai-Thinker-Open_ESP32-CAMERA_WAN
CAM SDK失败,可试用一下指令
cd esp-idf
git clone --recurse-submodules https://github.com.cnpmjs.org/Ai-Thinker-Open/Ai-Thinker-Open_ESP32-CAMERA_WAN
3.2 编译下载
cd Ai-Thinker-Open_ESP32-CAMERA_WAN
make menuconfig
进入Camera configuration —>
输入Nabto ID 为"asrrmhso.zuzcni.trial.nabto.net"
Nabto key为"337acb58e15b72117a49bf779d90cb29"
进入Setup correct wiring of camera ,选择Seedstudios/AI.Tinker
使能smartconfig,进入 smart config,输入Y使能,上电即可使用app配网,配网app获取
如果固定使用一个WiFi,可在WIFI access point name (SSID)输入WiFi名字,在 WIFI password输入WiFi密码,写死WiFi信息后无需app配网。
make //编译
make flash //下载
make monitor //串口打印
四、配网 && APP查看视频
- 如果写死wifi信息可略过此配网步骤。smartconfig配网过程如下图:
- 确保手机和设备接入同一WiFi,进入app,点击discover and auto pair with device
- 发现设备后点击右侧箭头进入
- 确认配对
- 进入设备即可查看视频
- 配对过后下次进入app直接在首页点击进入即可,如果没有发现设备,点击REFRESH刷新一下
五、smartconfig配网后SSID,password保存
截至2020/12/2 在sdk里面仅提供smartconfig示例,配网成功后并没有保存WiFi信息。这里提供smartconfig配网成功后保存SSID、Password的示例,配网成功后自动保存ssid和password,上电自动连接上一次连接的WiFi。
- 配网成功后将WiFi信息写入flash
void router_wifi_save_info(uint8_t *ssid, uint8_t *password)
{
nvs_handle out_handle;
char data[65];
if (nvs_open("wifi_info", NVS_READWRITE, &out_handle) != ESP_OK)
{
return;
}
memset(data, 0x0, sizeof(data));
strncpy(data, (char *)ssid, strlen((char *)ssid));
if (nvs_set_str(out_handle, "ssid", data) != ESP_OK)
{
ESP_LOGI(TAG,"--set ssid fail");
}
memset(data, 0x0, sizeof(data));
strncpy(data, (char *)password, strlen((char *)password));
if (nvs_set_str(out_handle, "password", data) != ESP_OK)
{
ESP_LOGI(TAG,"--set password fail");
}
nvs_commit(out_handle);
nvs_close(out_handle);
}
- 上电后将flash中的WiFi信息读出
wifi_config_t wifi_config;
bool router_wifi_read()
{
nvs_handle out_handle;
size_t size = 0;
nvs_open("wifi_info", NVS_READONLY, &out_handle);
memset(&wifi_config, 0x0, sizeof(wifi_config));
size = sizeof(wifi_config.sta.ssid);
if(nvs_get_str(out_handle, "ssid", (char *)wifi_config.sta.ssid, &size) == ESP_OK)
{
if (size > 0)
{
size = sizeof(wifi_config.sta.password);
if (nvs_get_str(out_handle, "password", (char *)wifi_config.sta.password, &size) == ESP_OK)
{
ESP_LOGI(TAG,"-- get ssid: %s", wifi_config.sta.ssid);
ESP_LOGI(TAG,"-- get password: %s", wifi_config.sta.password);
return 1;
}
}
}
nvs_close(out_handle);
return 0;
}
- 修改后的main.c
#include <stdio.h>
#include <ctype.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_camera.h"
#include <driver/gpio.h>
#include <esp_http_server.h>
#include "demo_application.h"
#include <unabto_aes_cbc_test.h>
//#include <unabto_hmac_sha256_test.h>
#include <unabto/unabto_common_main.h>
#include <unabto/unabto_app.h>
#include <unabto_tunnel_select.h>
#include "app_smart_wifi.h"
#include "nvs_flash.h"
#include <stdbool.h>
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_err.h"
// Set in menuconfig .. or override here
#define WIFI_SSID CONFIG_SSID
#define WIFI_PASS CONFIG_SSID_PASSWORD
#define NABTO_ID CONFIG_NABTO_ID
#define NABTO_KEY CONFIG_NABTO_KEY
// Event group
//static EventGroupHandle_t wifi_event_group;
EventGroupHandle_t wifi_event_group;
const int CONNECTED_BIT = BIT0;
bool router_wifi_read();
void router_wifi_save_info(uint8_t *ssid, uint8_t *password);
wifi_config_t wifi_config;
static const char *TAG = "main";
#ifdef CONFIG_ESP_EYE
// ESP-EYE wiring
#define CAM_PIN_PWDN -1 //power down is not used
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 4
#define CAM_PIN_SIOD 18
#define CAM_PIN_SIOC 23
#define CAM_PIN_D7 36
#define CAM_PIN_D6 37
#define CAM_PIN_D5 38
#define CAM_PIN_D4 39
#define CAM_PIN_D3 35
#define CAM_PIN_D2 14
#define CAM_PIN_D1 13
#define CAM_PIN_D0 34
#define CAM_PIN_VSYNC 5
#define CAM_PIN_HREF 27
#define CAM_PIN_PCLK 25
#elif defined CONFIG_ESP_TINKER
// Ai Thinker CAM 32 wiring
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
#elif CONFIG_M5CAMERA_A
#define CAM_PIN_PWDN -1 //power down is not used
#define CAM_PIN_RESET 15 //software reset will be performed
#define CAM_PIN_XCLK 27
#define CAM_PIN_SIOD 25
#define CAM_PIN_SIOC 23
#define CAM_PIN_D7 19
#define CAM_PIN_D6 36
#define CAM_PIN_D5 18
#define CAM_PIN_D4 39
#define CAM_PIN_D3 5
#define CAM_PIN_D2 34
#define CAM_PIN_D1 35
#define CAM_PIN_D0 32
#define CAM_PIN_VSYNC 22
#define CAM_PIN_HREF 26
#define CAM_PIN_PCLK 21
#else
#error "Not defined - this should not happed!"
#endif
#define CAM_XCLK_FREQ 20000000
static camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
.pin_reset = CAM_PIN_RESET,
.pin_xclk = CAM_PIN_XCLK,
.pin_sscb_sda = CAM_PIN_SIOD,
.pin_sscb_scl = CAM_PIN_SIOC,
.pin_d7 = CAM_PIN_D7,
.pin_d6 = CAM_PIN_D6,
.pin_d5 = CAM_PIN_D5,
.pin_d4 = CAM_PIN_D4,
.pin_d3 = CAM_PIN_D3,
.pin_d2 = CAM_PIN_D2,
.pin_d1 = CAM_PIN_D1,
.pin_d0 = CAM_PIN_D0,
.pin_vsync = CAM_PIN_VSYNC,
.pin_href = CAM_PIN_HREF,
.pin_pclk = CAM_PIN_PCLK,
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
.xclk_freq_hz = CAM_XCLK_FREQ,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = FRAMESIZE_VGA,//QQVGA-QXGA Do not use sizes above QVGA when not JPEG
.jpeg_quality = 10, //0-63 lower number means higher quality
.fb_count = 5 //if more than one, i2s runs in continuous mode. Use only with JPEG //{ 2
};
// #ifndef CONFIG_ESP_SMAERT_CONFIG
/*
* WIFI event handler
*/
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_GOT_IP:
NABTO_LOG_INFO(("connected1!\n"));
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
esp_wifi_connect();
break;
default:
break;
}
return ESP_OK;
}
// #endif
/*
* Convert hex to i (for converting the hex key to bytebuffer)
*/
int hctoi(const unsigned char h) {
if (isdigit(h)) {
return h - '0';
} else {
return toupper(h) - 'A' + 10;
}
}
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
/*
* MJPEG stream handler on http://<host>/
*/
esp_err_t jpg_stream_httpd_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len;
uint8_t * _jpg_buf;
char * part_buf[64];
static int64_t last_frame = 0;
if(!last_frame) {
last_frame = esp_timer_get_time();
}
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
while(true){
fb = esp_camera_fb_get();
if (!fb) {
NABTO_LOG_ERROR(("Camera capture failed"));
res = ESP_FAIL;
} else {
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
if(!jpeg_converted){
NABTO_LOG_ERROR(("JPEG compression failed"));
esp_camera_fb_return(fb);
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
}
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb->format != PIXFORMAT_JPEG){
free(_jpg_buf);
}
esp_camera_fb_return(fb);
if(res != ESP_OK){
break;
}
int64_t fr_end = esp_timer_get_time();
int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000;
NABTO_LOG_INFO(("MJPG: %uKB %ums (%.1ffps)",
(uint32_t)(_jpg_buf_len/1024),
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time));
}
last_frame = 0;
return res;
}
/*
* Hello world on http://<host>/uri
*/
esp_err_t get_handler(httpd_req_t *req)
{
/* Send a simple response */
const char* resp = "Hello world test!";
httpd_resp_send(req, resp, strlen(resp));
return ESP_OK;
}
/*
* 1m stream of bytes on http://<host>/1m for stream performance testing
*/
esp_err_t get_handler_1m(httpd_req_t *req)
{
/* Send a simple response */
const char* resp =
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n" \
"0123456789012345678901234567890123456789012345678\n";
// Create a 1k byte buffer chuck
char resp_1k[1000];
int len = 1000;
for(int i=0;i<10;i++) {
memcpy(resp_1k+(i*100), resp, 100);
}
resp_1k[999]=0;
NABTO_LOG_INFO(("strlen:%d 1000000/len:%d", len, 1000000/len));
int64_t start_time = esp_timer_get_time();
// Send 1m chunk
for(int t=0; t< 1000000/len; t++) {
int res = httpd_resp_send_chunk(req, (const char *) resp_1k, len);
if(res != ESP_OK) {
NABTO_LOG_INFO(("Could not send chunk %i", t));
return ESP_FAIL;
}
}
// send last 0 chunk to end the stream
httpd_resp_send_chunk(req, (const char *) resp, 0);
int64_t end_time = esp_timer_get_time();
int64_t time = end_time - start_time;
float kb = 1000000/1024;
NABTO_LOG_INFO(("Finished in %lldms kb=%f kb/s=%f", time/1000, kb, kb/((float)time/1000000)));
return ESP_OK;
}
/* URI handler structure for GET /uri */
httpd_uri_t uri_get = {
.uri = "/uri",
.method = HTTP_GET,
.handler = get_handler,
.user_ctx = NULL
};
/* URI handler structure for GET /1m */
httpd_uri_t uri_get_1m = {
.uri = "/1m",
.method = HTTP_GET,
.handler = get_handler_1m,
.user_ctx = NULL
};
/* URI handler structure for GET / */
httpd_uri_t uri_get_mjpeg = {
.uri = "/",
.method = HTTP_GET,
.handler = jpg_stream_httpd_handler,
.user_ctx = NULL
};
/*
* Function for starting the webserver
*/
httpd_handle_t start_webserver(void)
{
/* Generate default configuration */
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = 8081;
/* Empty handle to esp_http_server */
httpd_handle_t server = NULL;
/* Start the httpd server */
if (httpd_start(&server, &config) == ESP_OK) {
/* Register URI handlers */
httpd_register_uri_handler(server, &uri_get);
httpd_register_uri_handler(server, &uri_get_1m);
httpd_register_uri_handler(server, &uri_get_mjpeg);
}
/* If server failed to start, handle will be NULL */
return server;
}
/*
* Function for stopping the webserver (not used)
*/
void stop_webserver(httpd_handle_t server)
{
if (server) {
/* Stop the httpd server */
httpd_stop(server);
}
}
/*
* Main task - initialize WIFI and start Nabto tick
*/
void main_task(void *pvParameter)
{
// device id and key from developer.nabto.com
const char* nabtoId = NABTO_ID;
const char* presharedKey = NABTO_KEY;
NABTO_LOG_INFO(("NabtoId:%s", nabtoId));
NABTO_LOG_INFO(("NabtoKey:%s", presharedKey));
// wait for connection
NABTO_LOG_INFO(("Main task: waiting for connection to the wifi network... "));
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
NABTO_LOG_INFO(("connected!\n"));
// print the local IP address
tcpip_adapter_ip_info_t ip_info;
ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
NABTO_LOG_INFO(("IP Address: %s", ip4addr_ntoa(&ip_info.ip)));
NABTO_LOG_INFO(("Subnet mask: %s", ip4addr_ntoa(&ip_info.netmask)));
NABTO_LOG_INFO(("Gateway: %s", ip4addr_ntoa(&ip_info.gw)));
// Start the webserver thread
start_webserver();
// Configure Nabto with the right configuration
nabto_main_setup* nms = unabto_init_context();
nms->id = NABTO_ID;
//nms->ipAddress = ip_info.ip.addr;
nms->id = nabtoId;
nms->secureAttach = 1;
nms->secureData = 1;
nms->cryptoSuite = CRYPT_W_AES_CBC_HMAC_SHA256;
const char* p;
unsigned char* up;
for (p = presharedKey, up = nms->presharedKey; *p; p += 2, ++up) {
*up = hctoi(p[0]) * 16 + hctoi(p[1]); // hex string to byte array
}
// Init demo application
demo_init();
tunnel_loop_select();
}
void router_wifi_save_info(uint8_t *ssid, uint8_t *password)
{
nvs_handle out_handle;
char data[65];
if (nvs_open("wifi_info", NVS_READWRITE, &out_handle) != ESP_OK)
{
return;
}
memset(data, 0x0, sizeof(data));
strncpy(data, (char *)ssid, strlen((char *)ssid));
if (nvs_set_str(out_handle, "ssid", data) != ESP_OK)
{
ESP_LOGI(TAG,"--set ssid fail");
}
memset(data, 0x0, sizeof(data));
strncpy(data, (char *)password, strlen((char *)password));
if (nvs_set_str(out_handle, "password", data) != ESP_OK)
{
ESP_LOGI(TAG,"--set password fail");
}
nvs_commit(out_handle);
nvs_close(out_handle);
}
bool router_wifi_read()
{
nvs_handle out_handle;
size_t size = 0;
nvs_open("wifi_info", NVS_READONLY, &out_handle);
memset(&wifi_config, 0x0, sizeof(wifi_config));
size = sizeof(wifi_config.sta.ssid);
if(nvs_get_str(out_handle, "ssid", (char *)wifi_config.sta.ssid, &size) == ESP_OK)
{
if (size > 0)
{
size = sizeof(wifi_config.sta.password);
if (nvs_get_str(out_handle, "password", (char *)wifi_config.sta.password, &size) == ESP_OK)
{
ESP_LOGI(TAG,"-- get ssid: %s", wifi_config.sta.ssid);
ESP_LOGI(TAG,"-- get password: %s", wifi_config.sta.password);
return 1;
}
}
}
nvs_close(out_handle);
return 0;
}
void wifi_connet(void)
{
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
}
/*
* Main application entry
*/
void app_main()
{
NABTO_LOG_INFO(("Nabto ESP32 demo starting up!!!"));
NABTO_LOG_INFO(("Initializing nvs flash"));
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
NABTO_LOG_INFO(("Erasing flash"));
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
//initialize the camera
NABTO_LOG_INFO(("Initializing camera"));
#if CAMERA_WIRING==ESP_EYE
/* IO13, IO14 is designed for JTAG by default,
* to use it as generalized input,
* firstly declair it as pullup input */
gpio_config_t conf;
conf.mode = GPIO_MODE_INPUT;
conf.pull_up_en = GPIO_PULLUP_ENABLE;
conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
conf.intr_type = GPIO_INTR_DISABLE;
conf.pin_bit_mask = 1LL << 13;
gpio_config(&conf);
conf.pin_bit_mask = 1LL << 14;
gpio_config(&conf);
#endif
ret = esp_camera_init(&camera_config);
if (ret != ESP_OK) {
NABTO_LOG_ERROR(("Camera Init Failed"));
}
// disable stdout buffering
setvbuf(stdout, NULL, _IONBF, 0);
/*
NABTO_LOG_INFO(("Testing AES adapter"));
if(!aes_cbc_test()) {
NABTO_LOG_ERROR(("!!!!!WARNING... AES test not completed"));
}
NABTO_LOG_INFO(("Testing SHA adapter"));
if(!hmac_sha256_test()) {
NABTO_LOG_ERROR(("!!!!!WARNING... HMAC_SHA256 test not completed"));
}
*/
// create the event group to handle wifi events
wifi_event_group = xEventGroupCreate();
#ifdef CONFIG_ESP_SMAERT_CONFIG
if(router_wifi_read()==0){
initialise_wifi();
}
else{
wifi_connet();
}
#else
// initialize the tcp stack
tcpip_adapter_init();
// initialize the wifi event handler
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
// initialize the wifi stack in STAtion mode with config in RAM
wifi_init_config_t wifi_init_config = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&wifi_init_config));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
// configure the wifi connection and start the interface
wifi_config_t wifi_config = {
.sta = {
.ssid = WIFI_SSID,
.password = WIFI_PASS,
},
};
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
#endif
NABTO_LOG_INFO(("Connecting to %s\n", WIFI_SSID));
// start the main task
xTaskCreate(&main_task, "main_task", 8192, NULL, 5, NULL);
// Go do something else here
}
- 修改后的app_smart_wifi.c
/* Esptouch example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "esp_smartconfig.h"
#include <time.h>
#include <sys/time.h>
#include "esp_sntp.h"
#include "sdkconfig.h"
extern void router_wifi_save_info(uint8_t *ssid, uint8_t *password);
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t s_wifi_event_group;
extern EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "smartconfig_example";
static void smartconfig_example_task(void * parm);
uint8_t ssid[33] = { 0 };
uint8_t password[65] = { 0 };
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
//esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
//xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
ESP_LOGI(TAG, "Scan done");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
ESP_LOGI(TAG, "Found channel");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
ESP_LOGI(TAG, "Got SSID and password");
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config;
bzero(&wifi_config, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
wifi_config.sta.bssid_set = evt->bssid_set;
if (wifi_config.sta.bssid_set == true) {
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
}
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
ESP_LOGI(TAG, "SSID:%s", ssid);
ESP_LOGI(TAG, "PASSWORD:%s", password);
// router_wifi_save_info(ssid,password);
ESP_ERROR_CHECK( esp_wifi_disconnect() );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_connect() );
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
}
}
void time_sync_notification_cb(struct timeval *tv)
{
ESP_LOGI(TAG, "SNTP OK ");
}
static void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH
sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH);
#endif
sntp_init();
}
static void smartconfig_example_task(void * parm)
{
EventBits_t uxBits;
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
while (1) {
uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
if(uxBits & CONNECTED_BIT) {
ESP_LOGI(TAG, "WiFi Connected to ap");
}
if(uxBits & ESPTOUCH_DONE_BIT) {
ESP_LOGI(TAG, "smartconfig over");
router_wifi_save_info(ssid,password);
#if CONFIG_ESP_SNTP_ENABLED
{
initialize_sntp();
// wait for time to be set
time_t now = 0;
struct tm timeinfo = { 0 };
int retry = 0;
const int retry_count = 10;
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
//ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
time(&now);
localtime_r(&now, &timeinfo);
}
#endif
//LOG_INFO(("connected1!\n"));
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
esp_smartconfig_stop();
vTaskDelete(NULL);
}
}
}
void initialise_wifi(void)
{
tcpip_adapter_init();
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
六、总结
ESP32-S模组驱动摄像头ov2640,20MHz的时钟频率,图像格式为JPEG,分辨率VGA 640*480,帧率
平均15帧/s,上传速率为150KB/s~300KB/s(此数据是接入手机的热点,网络环境良好情况下更佳);
同时拍照图片时最大的分辨率为1600*1200;总体来说此次demo还是比较理想,同时还有很多优化的空
间留给码友们。
测试固件(smartconfig配网),点我下载