# softAP **Repository Path**: jinbo1/softAP ## Basic Information - **Project Name**: softAP - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-01-08 - **Last Updated**: 2026-01-12 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ESP32 SoftAP 摄像头项目 ## 项目概述 这是一个基于 ESP32 的 WiFi 软接入点(SoftAP)项目,集成了摄像头视频流、HTTP Web 服务器和 LED 控制功能。项目使用 ESP-IDF 5.3.2 开发框架,支持通过 Web 界面实时查看摄像头画面并控制 LED 设备。 ## 功能特性 ### 1. WiFi 软接入点(SoftAP) - 创建独立的 WiFi 热点 - 支持 WPA2/WPA3 安全认证 - 可配置 SSID、密码、信道和最大连接数 - 默认 IP 地址:`192.168.4.1` - **Captive Portal(强制门户)**:手机连接热点后,浏览器自动弹出页面 - 自动启动 DNS 服务器(端口 53),将所有域名解析到 ESP32 - HTTP 服务器自动重定向所有未匹配请求到主页 - 📖 [详细实现原理文档](CAPTIVE_PORTAL.md) ### 2. HTTP Web 服务器 - 监听端口:80 - 提供 Web 界面(HTML + JavaScript) - 支持 CORS 跨域访问 - 单服务器实例设计,避免 socket 耗尽问题 ### 3. 摄像头视频流 - **WebSocket 流**:`ws://192.168.4.1/ws`(推荐) - 使用 WebSocket 协议传输二进制 JPEG 数据 - 低延迟,适合实时视频流 - 帧率:约 5fps(可调整) - **MJPEG 流**:`http://192.168.4.1/camera`(兼容模式) - 使用 HTTP multipart/x-mixed-replace 协议 - 兼容性更好,支持更多浏览器 - 帧率:约 10fps - **摄像头配置**: - 分辨率:XGA (1024x768) - 在 `camera.c` 中配置为 `FRAMESIZE_XGA` - 格式:JPEG - 质量:10(高质量) - 帧缓冲区:PSRAM(1个缓冲区) - 抓取模式:`CAMERA_GRAB_WHEN_EMPTY` ### 4. LED 控制 - **LED1**(GPIO 2): - 简单的开关控制 - API:`GET /led1/toggle` - 切换开关 - API:`GET /led1/status` - 查询状态 - **LED2**(GPIO 4): - 支持开关和亮度调节(PWM 控制) - 亮度范围:0-100% - PWM 频率:25kHz(8位分辨率) - API:`GET /led2/toggle` - 切换开关(智能记忆亮度) - API:`GET /led2/status` - 查询状态和亮度 - API:`GET /led2/brightness?value=0-100` - 设置亮度 ### 5. 内存监控 - 实时监控 PSRAM、DRAM 和堆内存使用情况 - 每 10 秒输出一次内存状态日志 - 支持内存使用率警告 ## 硬件要求 ### 支持的 ESP32 芯片 - ESP32(主要目标) - ESP32-S2 - ESP32-S3 ### 摄像头模块 项目使用 `espressif/esp32-camera` 驱动,支持以下摄像头传感器: - OV2640(推荐,1600x1200) - OV3660(2048x1536) - OV5640(2592x1944) - OV7670(640x480) - OV7725(640x480) - NT99141(1280x720) - GC032A(640x480) - GC0308(640x480) - GC2145(1600x1200) - 以及其他兼容的传感器 ### 引脚连接 #### 摄像头引脚(在 `camera.c` 中定义) ``` PWDN -> GPIO 32 RESET -> -1 (软件复位) XCLK -> GPIO 0 SIOD -> GPIO 26 (I2C SDA) SIOC -> GPIO 27 (I2C SCL) D7 -> GPIO 35 D6 -> GPIO 34 D5 -> GPIO 39 D4 -> GPIO 36 D3 -> GPIO 21 D2 -> GPIO 19 D1 -> GPIO 18 D0 -> GPIO 5 VSYNC -> GPIO 25 HREF -> GPIO 23 PCLK -> GPIO 22 ``` #### LED 引脚(在 `io_control.c` 中定义) ``` LED1 -> GPIO 2 (简单开关) LED2 -> GPIO 4 (PWM 控制,LEDC_TIMER_1, LEDC_CHANNEL_1) ``` ### 内存要求 - **PSRAM**:强烈推荐,用于摄像头帧缓冲区 - **Flash**:至少 4MB(推荐 8MB 或更大) ## 软件要求 - **ESP-IDF**:5.3.2 - **依赖组件**: - `espressif/esp32-camera`:2.0.8 - **编译工具**:CMake 3.16+ ## 项目结构 ``` softAP/ ├── main/ # 主程序目录 │ ├── main.c # 程序入口,初始化流程 │ ├── softap_example_main.c # WiFi AP 初始化 │ ├── softap_example_main.h # WiFi AP 头文件 │ ├── http_server.c # HTTP 服务器实现 │ ├── http_server.h # HTTP 服务器头文件 │ ├── camera.c # 摄像头驱动封装 │ ├── camera.h # 摄像头头文件 │ ├── io_control.c # IO 控制(LED) │ ├── io_control.h # IO 控制头文件 │ ├── dns_server.c # DNS 服务器(Captive Portal) │ ├── dns_server.h # DNS 服务器头文件 │ ├── index.html # Web 界面 HTML │ ├── CMakeLists.txt # 组件构建配置 │ ├── Kconfig.projbuild # 项目配置菜单 │ └── idf_component.yml # 组件依赖声明 ├── managed_components/ # 管理的组件(自动下载) │ └── espressif__esp32-camera/ # 摄像头驱动组件 ├── build/ # 构建输出目录 ├── CMakeLists.txt # 项目根构建配置 ├── sdkconfig # ESP-IDF 配置文件 ├── dependencies.lock # 依赖锁定文件 ├── README.md # 本文件 └── CHANGELOG.md # 修改日志 ``` ## 编译和烧录 ### 1. 环境准备 确保已安装 ESP-IDF 5.3.2 并设置好环境变量: ```bash # Windows cd %IDF_PATH% install.bat export.bat # Linux/macOS . $IDF_PATH/export.sh ``` ### 2. 配置项目 运行配置菜单: ```bash idf.py menuconfig ``` 在 `Example Configuration` 菜单中配置: - **WiFi SSID**:AP 的网络名称(默认:`myssid`) - **WiFi Password**:AP 的密码(默认:`mypassword`) - **WiFi Channel**:WiFi 信道(1-13,默认:1) - **Maximal STA connections**:最大客户端连接数(默认:4) - **Captive Portal Test Domain**:测试域名(默认:`test.com`) - 注意:DNS 服务器会将所有域名都解析到 ESP32,所以访问任何域名都可以 - 这个配置主要用于日志和文档参考 ### 3. 编译项目 ```bash idf.py build ``` **注意**:如果遇到 "There is no build directory to clean, exiting!" 错误,这是因为从 git 克隆的项目还没有 `build` 目录。解决方法: - **直接运行 `idf.py build`**,不需要先执行 `idf.py clean` 或 `idf.py fullclean` - 首次构建时会自动创建 `build` 目录 ### 4. 烧录到设备 ```bash idf.py -p PORT flash ``` 其中 `PORT` 是串口设备路径: - Windows: `COM3`, `COM4` 等 - Linux: `/dev/ttyUSB0`, `/dev/ttyACM0` 等 - macOS: `/dev/cu.usbserial-*`, `/dev/cu.SLAB_USBtoUART` 等 ### 5. 监控串口输出 ```bash idf.py -p PORT monitor ``` 或者一次性执行编译、烧录和监控: ```bash idf.py -p PORT flash monitor ``` 退出监控:按 `Ctrl+]` ## 使用方法 ### 1. 启动设备 1. 将程序烧录到 ESP32 并上电 2. 等待设备初始化完成(约 3-5 秒) 3. 查看串口输出,确认 WiFi AP 已启动: ``` I (xxx) wifi softAP: wifi_init_softap finished. SSID:myssid password:mypassword channel:1 I (xxx) wifi softAP: AP IP Address: 192.168.4.1 ``` ### 2. 连接 WiFi 1. 在手机或电脑上搜索 WiFi 网络 2. 找到配置的 SSID(默认:`myssid`) 3. 输入密码(默认:`mypassword`)并连接 4. 设备会自动获得 IP 地址(如:`192.168.4.2`) ### 3. 访问 Web 界面 **方式一:自动弹出(Captive Portal)** - 连接 WiFi 后,手机会自动检测网络连接 - 浏览器会自动弹出登录页面(Captive Portal) - 点击"登录"或"使用网络"即可访问 **方式二:手动访问** - 在浏览器中打开:`http://192.168.4.1` - 或访问任意网址(会被自动重定向到主页) Web 界面功能: - **视频流显示**:自动连接 WebSocket 并显示摄像头画面 - **LED1 控制**:点击按钮切换 LED1 开关 - **LED2 控制**:点击按钮切换 LED2 开关,拖动滑块调节亮度(0-100%) ### 4. API 接口 #### 视频流 - **WebSocket**:`ws://192.168.4.1/ws` - 连接后自动开始传输 JPEG 帧 - 数据格式:二进制(Binary) - **MJPEG**:`http://192.168.4.1/camera` - 在浏览器中直接打开即可查看视频流 - 格式:`multipart/x-mixed-replace` #### LED 控制 - **LED1 切换**:`GET /led1/toggle` - 返回:`{"state":true/false}` - **LED1 状态**:`GET /led1/status` - 返回:`{"state":true/false}` - **LED2 切换**:`GET /led2/toggle` - 返回:`{"state":true/false,"brightness":0-100}` - 智能切换:关闭时恢复上次亮度,开启时关闭 - **LED2 状态**:`GET /led2/status` - 返回:`{"state":true/false,"brightness":0-100}` - **LED2 亮度**:`GET /led2/brightness?value=50` - 参数:`value`(0-100) - 返回:`{"brightness":50}` ## Captive Portal(强制门户) Captive Portal 功能使手机连接 WiFi 热点后,浏览器自动弹出页面,无需手动输入 IP 地址。 **实现原理**:通过 DNS 服务器将所有域名解析到 ESP32,然后 HTTP 服务器将请求重定向到主页。 📖 **详细实现文档**:请参阅 [CAPTIVE_PORTAL.md](CAPTIVE_PORTAL.md) ## 代码架构 ### 模块说明 #### 1. `main.c` - 主程序入口 - 初始化 NVS(非易失性存储) - 初始化 IO 控制(LED) - 启动 WiFi AP - 初始化摄像头 - 启动 HTTP 服务器 - 主循环:定期喂看门狗和打印内存状态 #### 2. `softap_example_main.c` - WiFi AP 模块 - 初始化网络接口和事件循环 - 配置 WiFi AP 参数 - 处理 WiFi 事件(客户端连接/断开) - 输出 AP IP 地址信息 #### 3. `http_server.c` - HTTP 服务器模块 - 实现 HTTP 请求处理器: - `/` - 返回 HTML 页面 - `/ws` - WebSocket 视频流 - `/camera` - MJPEG 视频流 - `/led1/toggle` - LED1 切换 - `/led1/status` - LED1 状态 - `/led2/toggle` - LED2 切换 - `/led2/status` - LED2 状态 - `/led2/brightness` - LED2 亮度设置 - 视频流任务管理 - CORS 支持 - Captive Portal 重定向处理 #### 4. `dns_server.c` - DNS 服务器模块 - 实现 UDP DNS 服务器(端口 53) - 将所有 DNS 查询解析到 ESP32 的 IP 地址 - 支持 Captive Portal 功能,使设备自动弹出登录页面 #### 5. `camera.c` - 摄像头模块 - 摄像头初始化和配置 - 图像捕获和释放 - 引脚定义和硬件抽象 #### 6. `io_control.c` - IO 控制模块 - LED GPIO 初始化 - LED1:简单开关控制 - LED2:PWM 亮度控制(LEDC) - LED 状态管理 ### 关键设计决策 1. **单 HTTP 服务器实例**:避免 socket 资源耗尽,所有服务共享端口 80 2. **PSRAM 帧缓冲区**:摄像头帧存储在 PSRAM,节省 DRAM 3. **WebSocket + MJPEG 双模式**:提供最佳兼容性和性能 4. **任务优先级管理**:摄像头任务优先级高于视频流任务 5. **看门狗管理**:在长时间操作中定期重置看门狗,防止系统重启 ## 配置说明 ### 摄像头配置(`camera.c`) ```c camera_config_t camera_config = { .frame_size = FRAMESIZE_XGA, // 分辨率:1024x768 .jpeg_quality = 10, // JPEG 质量(0-63,越小质量越高) .fb_count = 1, // 帧缓冲区数量 .grab_mode = CAMERA_GRAB_WHEN_EMPTY, .fb_location = CAMERA_FB_IN_PSRAM, // 使用 PSRAM .xclk_freq_hz = 20000000, // XCLK 频率:20MHz }; ``` ### HTTP 服务器配置(`http_server.c`) ```c httpd_config_t config = { .server_port = 80, .max_uri_handlers = 10, .max_open_sockets = 7, // 最大连接数 .stack_size = 32768, // 任务栈大小 .task_priority = 5, .lru_purge_enable = true, // 启用 LRU 清理 .recv_wait_timeout = 5, // 接收超时 5 秒 .send_wait_timeout = 5, // 发送超时 5 秒 }; ``` ### LED PWM 配置(`io_control.c`) ```c // LED2 PWM 配置 #define LED2_LEDC_TIMER LEDC_TIMER_1 #define LED2_LEDC_CHANNEL LEDC_CHANNEL_1 #define LED2_LEDC_DUTY_RES LEDC_TIMER_8_BIT // 8位分辨率(0-255) #define LED2_LEDC_FREQUENCY 25000 // 25kHz ``` ## 性能优化 ### 已实现的优化 1. **内存优化**: - 使用 PSRAM 存储摄像头帧,减少 DRAM 压力 - 单帧缓冲区设计,降低内存占用 - 及时释放帧缓冲区 2. **网络优化**: - WebSocket 二进制传输,减少协议开销 - 分块发送大图像(8KB chunks) - 任务 yield,避免阻塞其他请求 3. **帧率控制**: - WebSocket:200ms 延迟(约 5fps) - MJPEG:100ms 延迟(约 10fps) - 可调整延迟以平衡性能和资源使用 4. **错误处理**: - 失败计数机制,避免无限重试 - 连接断开检测,及时释放资源 - 看门狗管理,防止系统卡死 ### 可进一步优化的方向 1. **帧率提升**:减少延迟时间,但会增加 CPU 和内存压力 2. **多缓冲区**:增加 `fb_count` 可提高流畅度,但占用更多内存 3. **分辨率调整**:降低分辨率可提高帧率和减少带宽 4. **JPEG 质量**:降低质量可减少数据量,但影响画质 ## 故障排除 ### 常见问题 #### 1. 摄像头初始化失败 **症状**:串口输出 `Camera init failed` **可能原因**: - 摄像头模块未正确连接 - 引脚配置不匹配 - I2C 通信失败 - 内存不足 **解决方法**: - 检查摄像头引脚连接 - 确认 `camera.c` 中的引脚定义正确 - 检查是否有 PSRAM - 查看详细错误代码(串口输出) #### 2. WiFi AP 无法启动 **症状**:无法搜索到 WiFi 网络 **可能原因**: - WiFi 配置错误 - 硬件问题 **解决方法**: - 检查 `sdkconfig` 或通过 `menuconfig` 配置 WiFi 参数 - 确认 ESP32 WiFi 功能正常 #### 3. 视频流无法显示 **症状**:Web 界面显示黑屏或连接失败 **可能原因**: - 摄像头未初始化 - WebSocket 连接失败 - 网络问题 **解决方法**: - 检查串口日志,确认摄像头已初始化 - 检查浏览器控制台错误信息 - 尝试使用 MJPEG 流(`/camera`)作为备选 #### 3.5. Captive Portal 不工作 **症状**:手机连接 WiFi 后,浏览器没有自动弹出页面 **可能原因**: - DNS 服务器未启动 - 手机系统禁用了自动检测 - 防火墙或安全软件阻止 **解决方法**: - 检查串口日志,确认 DNS 服务器已启动(应看到 "DNS server started on port 53") - 手动打开浏览器访问任意网址(如 `http://test.com` 或配置的测试域名),应该会自动重定向 - 注意:DNS 服务器会将所有域名都解析到 ESP32,所以访问任何域名都可以 - 某些手机需要在 WiFi 设置中点击"登录"或"使用网络" - 如果仍不工作,可以手动访问 `http://192.168.4.1` #### 4. LED 不工作 **症状**:LED 无响应 **可能原因**: - GPIO 引脚配置错误 - LED 硬件连接问题 - PWM 配置冲突 **解决方法**: - 检查 `io_control.c` 中的引脚定义 - 确认 LED 正确连接到 GPIO - 检查 LEDC 资源是否与摄像头冲突(LED2 使用 TIMER_1 和 CHANNEL_1) #### 5. 内存不足 **症状**:系统重启或功能异常 **可能原因**: - PSRAM 未启用或不足 - 帧缓冲区过大 - 内存泄漏 **解决方法**: - 确认 ESP32 支持并启用了 PSRAM - 降低摄像头分辨率 - 检查内存使用日志 ### 调试技巧 1. **查看串口日志**: ```bash idf.py -p PORT monitor ``` 日志级别可在 `menuconfig` 中调整 2. **内存监控**: 主循环每 10 秒输出内存状态,观察内存使用趋势 3. **网络调试**: 使用浏览器开发者工具(F12)查看网络请求和 WebSocket 连接 4. **GPIO 测试**: 可以临时修改代码,直接控制 GPIO 测试硬件连接 ## 开发指南 ### 修改摄像头分辨率 编辑 `main/camera.c`: ```c .frame_size = FRAMESIZE_VGA, // 改为 VGA (640x480) // 或 .frame_size = FRAMESIZE_SVGA, // SVGA (800x600) // 或 .frame_size = FRAMESIZE_HD, // HD (1280x720) ``` ### 修改视频流帧率 编辑 `main/http_server.c`: ```c // WebSocket 流延迟(在 ws_video_task 函数中) vTaskDelay(pdMS_TO_TICKS(200)); // 改为更小的值可提高帧率 // MJPEG 流延迟(在 camera_get_handler 函数中) vTaskDelay(pdMS_TO_TICKS(100)); // 改为更小的值可提高帧率 ``` ### 添加新的 API 端点 1. 在 `http_server.c` 中实现处理函数 2. 在 `start_webserver()` 中注册 URI 处理器 示例: ```c static esp_err_t my_handler(httpd_req_t *req) { // 处理逻辑 httpd_resp_send(req, "OK", HTTPD_RESP_USE_STRLEN); return ESP_OK; } // 在 start_webserver() 中注册 httpd_uri_t my_uri = { .uri = "/myapi", .method = HTTP_GET, .handler = my_handler, }; httpd_register_uri_handler(server_handle, &my_uri); ``` ### 修改 LED 引脚 编辑 `main/io_control.c`: ```c #define LED1_GPIO_PIN 2 // 改为目标 GPIO(ESP32有效GPIO范围:0-19, 21-23, 25-27, 32-39) #define LED2_GPIO_PIN 4 // 改为目标 GPIO ``` 注意:LED2 使用 PWM,确保目标 GPIO 支持 LEDC 功能。 ## 版本历史 详见 [CHANGELOG.md](CHANGELOG.md) 主要版本: - **v1.0**:基础功能实现 - WiFi SoftAP - HTTP 服务器 - 摄像头视频流(MJPEG) - LED 控制 - **v1.1**:功能增强 - 添加 WebSocket 视频流 - LED2 亮度调节(PWM) - 内存监控 - 代码优化和清理 ## 许可证 本项目基于 ESP-IDF 示例代码,遵循相应的开源许可证。 ## 贡献 欢迎提交 Issue 和 Pull Request! ## 参考资料 - [ESP-IDF 官方文档](https://docs.espressif.com/projects/esp-idf/en/latest/) - [ESP32-Camera 驱动文档](https://github.com/espressif/esp32-camera) - [ESP-IDF HTTP 服务器 API](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/protocols/esp_http_server.html) - [ESP-IDF WiFi API](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_wifi.html) ## 联系方式 如有问题或建议,请通过以下方式联系: - 提交 GitHub Issue - 查看项目文档 --- **注意**:本项目仅供学习和参考使用。在生产环境中使用前,请进行充分测试和安全评估。