魔盒固件开发①:准备
日期:2025-12-15
目标:把官方 hello_world 工程改造成"魔盒"固件骨架,今天先完成环境验证与基础配置。
一、开发环境一览
| 项目 | 版本 / 来源 |
|---|---|
| 操作系统 | MAC OS |
| VS Code | 1.107 |
| ESP-IDF 插件 | v1.10.2(Espressif 官方) |
| ESP-IDF 核心 | v5.5.1(release 分支最新 tag) |
| 硬件 | ESP32-C3-DevKitM-1(4 MB Flash) |
二、安装与踩坑速记
1. 插件一键安装
① Ctrl+Shift+X → 搜索"Espressif IDF" → Install
② 按 F1 →ESP-IDF: Configure ESP-IDF extension→ 选择EXPRESS模式 → 选 5.5.1 → 自动下载工具链 & 环境变量。
③ 安装完毕打开终端,输入bash idf.py --version
看到ESP-IDF v5.5.1即成功。
2. 国内镜像加速(可选)
在安装向导里把https://github.com→https://hub.fastgit.org
可让工具链下载快 3-5 倍。
三、新建 hello_world 工程(图形化)
- F1 →
ESP-IDF: New Project- Template:hello_world
- 位置:
D:\magic-box\firmware\hello_world - 目标芯片:esp32c3
- 插件自动生成
.vscode\c_cpp_properties.json与launch.json,IntelliSense 零配置即可用。
四、menuconfig 三件套
进入工程根目录,按 F1 →ESP-IDF: SDK Configuration editor(即 menuconfig GUI)。
| 配置项 | 路径 | 值 | 说明 |
|---|---|---|---|
| Flash 大小 | Serial Flash Config→Flash size | 4 MB | 官方默认 2 MB,不改后面 OTA 会失败 |
| Flash 模式 | Flash SPI mode | DIO | DevKitM-1 硬件 strapping 决定 |
| Flash 频率 | Flash SPI speed | 80 MHz | 官方规格支持 |
| 系统日志 | Component config→Log output | Info | 调试用,量产可 Warning |
保存后会在sdkconfig里生成对应条目,等同于老版本idf.py menuconfig的.config。
五、v5.x 新坑:mDNS 组件需手动拉取
从 ESP-IDF v5.0 起,mDNS 被拆出主线仓库,必须显式声明依赖。
1. 一键添加
在项目根目录打开终端(VS Code 自带即可):
idf.py add-dependency espressif/mdns命令执行后:
会在工程根目录生成main\idf_component.yml
内容示例:
dependencies:espressif/mdns:"^1.4.0"首次编译时自动从 components.espressif.com 下载源码,无需翻墙。
2. 验证是否成功
在main\hello_world_main.c里随手引用:
#include"mdns.h"voidapp_main(void){mdns_init();// 若编译不报错 = 依赖 OKprintf("Hello mDNS!\n");}执行idf.py build能看到组件被拉取:
-- Found component "espressif/mdns" version 1.4.0六、编译 & 下载 & 监视
编译
idf.py build首次需 3-5 分钟,后续增量 20 s 左右。
下载
板子插 USB → 设备管理器出现 USB JTAG/serial debug unit
idf.py -p COMx flash串口监视
idf.py -p COMx monitor复位后应看到:
Hello mDNS! Hello world! Restarting in 10 seconds...MagicBox 固件(起步版)
基于 ESP-IDF 的 MagicBox 项目骨架:NVS 配置 + WiFi 管理(STA/AP 回退)+ Web 配网 + mDNS + 简单 REST API。
当前已实现
- NVS 存储:WiFi、MQTT、WS2812、GPIO、OTA URL 等配置
- 工厂复位:按键长按
>= 8s清空 NVS 并重启(默认 GPIO0,可在 Kconfig/NVS 修改) - 管理模式超时:上电/复位后进入管理模式,若长时间无 HTTP 访问会自动转入低功耗流程(默认 5 分钟空闲超时)
- WiFi:
- NVS 无配置 → 启动 AP(
MagicBox-XXXX)用于配网 - NVS 有配置 → STA 连接,失败 3 次后回退到 AP
- (可选)SmartConfig(EspTouch):当启用
CONFIG_MAGICBOX_ENABLE_SMARTCONFIG且无 WiFi 配置时,优先尝试 60s,失败回退 AP
- NVS 无配置 → 启动 AP(
- Web(httpd):
GET /管理页(WiFi/MQTT/WS2812/OTA 配置表单 + 常用操作)POST /wifi保存 WiFi 并重启POST /mqtt保存 MQTT 并重启POST /ws保存 WS2812 配置并重启POST /ota保存 OTA URLGET /api/status返回设备状态 JSONGET /api/config/POST /api/config获取/更新配置(JSON)POST /api/reboot重启、POST /api/factory_reset工厂复位、POST /api/sleep进入 deep sleepPOST /api/ota触发 OTA(使用已保存 URL 或 body 提供 url)POST /api/light点灯测试
- mDNS:STA 模式下广播
magicbox-<device_id>.local,服务_http._tcp端口 80 - WS2812(RMT):通过
led_strip驱动,支持单点点亮/清空(测试 API 与 MQTT 指令) - 5V 电源 KEY:GPIO 低电平脉冲 toggle(用于 WS2812 供电控制,按你的 CD42 KEY 逻辑)
- 动作模式(低功耗流程骨架):从 deep sleep 被传感器 GPIO 唤醒后,短暂联网订阅 MQTT → 执行点灯 → 熄灯/关 5V → 回到 deep sleep
使用方法
- 初始化环境:
source ~/esp/v5.5.1/esp-idf/export.sh - (可选)设置目标芯片:
idf.py set-target esp32c3 - 编译:
idf.py build - 烧录/监视:
idf.py -p PORT flash monitor - 配网:
- 手机/电脑连接 AP:
MagicBox-XXXX(默认无密码) - 打开
http://192.168.4.1/填写 SSID/Password,保存后设备重启
- 手机/电脑连接 AP:
- STA 成功后:
- 浏览器访问
http://magicbox-<device_id>.local/(或直接用 IP) - API:
GET http://<ip>/api/status
- 浏览器访问
GPIO/引脚配置
默认引脚来自menuconfig -> MagicBox(Kconfig),也可通过 Web 管理页表单或POST /api/config写入 NVS(见下方 NVS Key / API)。
| GPIO | 用途 | 默认值 | 备注 |
|---|---|---|---|
GPIO4 | 唤醒/人体存在输入(USRR235L) | CONFIG_MAGICBOX_GPIO_SENSOR | Deep sleep 唤醒脚(需选择支持 deep sleep wake 的引脚) |
GPIO5 | 5V 电源 KEY 控制(CD42 KEY) | CONFIG_MAGICBOX_GPIO_POWER_KEY | 低电平脉冲 toggle;睡眠前会 hold 为高电平 |
GPIO12 | WS2812 数据线 0 | CONFIG_MAGICBOX_GPIO_WS2812_DATA0 | 双 IO 之一;睡眠前会 hold 为低电平 |
GPIO13 | WS2812 数据线 1 | CONFIG_MAGICBOX_GPIO_WS2812_DATA1 | 双 IO 之一;睡眠前会 hold 为低电平 |
GPIO12 | WS2812 当前使用数据线 | CONFIG_MAGICBOX_WS2812_ACTIVE_GPIO | 实际使用gpio_ws;初始化失败会自动回退到另一条并写回 NVS |
GPIO0 | 工厂复位按键 | CONFIG_MAGICBOX_GPIO_FACTORY_RESET | 低电平有效,长按>= 8s清空 NVS 并重启 |
GPIO(-1) | 状态指示灯(可选) | CONFIG_MAGICBOX_GPIO_STATUS_LED | -1表示禁用;用于提示 MQTT 未配置/连接失败等(建议独立低电流 LED) |
接口速查
- 管理页:
GET / - 配网保存:
POST /wifi(application/x-www-form-urlencoded:ssid=...&password=...) - 状态:
GET /api/status - 配置:
GET /api/config、POST /api/config - OTA:
POST /api/ota(可选 body:{"url":"http(s)://..."}) - 睡眠:
POST /api/sleep - 点灯测试:
POST /api/light({"grid":1,"color":"#00FF00","duration":5})
MQTT 指令(动作模式)
- 订阅主题:
magicbox/<device_id>/commandmagicbox/all/command(广播)
- 权限边界(避免误配置):
- 设备专属 topic(
magicbox/<device_id>/command):允许light/clear/config/config_get/ota/reboot/sleep - 广播 topic(
magicbox/all/command):仅允许light/clear(其余会被忽略)
- 设备专属 topic(
- 状态主题(LWT + retain):
magicbox/<device_id>/status:{"state":"online","device_id":"..."}/{"state":"offline","device_id":"...","reason":"lwt"}
- ACK 主题(执行后上报):
magicbox/<device_id>/ack
id建议:- 建议统一使用单调递增的数字作为
id(例如1,2,3...),固件会将"最后处理的 id"持久化到 NVS,用于 deep sleep/重启后的离线队列去重。
- 建议统一使用单调递增的数字作为
action: "light"示例(建议带id,用于 QoS1 重投递去重与 ACK 对账):{"id":1,"action":"light","grid":5,"color":"#00FF00","duration":60}
action: "light"(上下堆叠寻址)示例:{"id":2,"action":"light","dir":"up","box":1,"grid":5,"color":"#00FF00","duration":60}(向上第 1 个盒子段,第 5 颗灯){"id":3,"action":"light","dir":"down","box":2,"grid":1,"color":"#FF0000","duration":30}(向下第 2 个盒子段,第 1 颗灯)
action: "light"(动画)示例:{"id":4,"action":"light","grid":1,"color":"#00FF00","duration":10,"effect":"blink","period":800}{"id":5,"action":"light","dir":"up","box":1,"grid":1,"color":"#00FF00","duration":10,"effect":"breathe"}{"id":6,"action":"light","dir":"down","box":1,"grid":1,"color":"#00FF00","duration":10,"effect":"chase","period":120}
action: "clear"示例:{"action":"clear"}
action: "config_get"示例(返回当前配置 JSON 到 ACK 主题;不包含密码明文):{"action":"config_get"}
action: "config"示例(字段与POST /api/config一致,写入 NVS;修改 WiFi/MQTT/WS/GPIO 默认会触发重启):{"action":"config","wifi":{"ssid":"MyWiFi","password":"12345678"},"reboot":true}{"action":"config","mqtt":{"uri":"mqtt://192.168.1.10:1883","username":"u","password":"p","client_id":"mb-001"},"reboot":true}{"action":"config","ws2812":{"led_count":12,"data_gpio":12},"reboot":true}{"action":"config","gpio":{"sensor":4,"power_key":5,"ws0":12,"ws1":13,"ws":12,"factory_reset":0},"reboot":true}{"action":"config","ota":{"url":"https://example.com/magicbox.bin"}}{"action":"config","stack":{"up":2,"down":1}}(设置向上/向下堆叠盒子数量,用于dir+box+grid寻址)
action: "ota"示例(可直接传url,或使用已保存的ota.url):{"action":"ota","url":"https://example.com/magicbox.bin"}
action: "reboot"/action: "sleep"示例:{"action":"reboot"}{"action":"sleep"}
NVS Key
- 命名空间:
magicbox wifi_ssid、wifi_passdevice_id(未设置时使用 WiFi STA MAC 生成)mqtt_uri、mqtt_user、mqtt_pass、mqtt_cidmqtt_last_id(MQTT 指令去重:最后处理的数字 id)ws_count、gpio_ws(WS2812 灯数与数据引脚)ws_pwr_ma、ws_max_on(WS2812 电源预算与"最大同时点亮灯数"估计,用于自动限亮)gpio_sensor、gpio_pwrkey、gpio_reset、gpio_ws0、gpio_ws1stk_up、stk_dn(上下堆叠盒子数量)stk_up_rev、stk_dn_rev(box 编号是否反向映射)ota_url
低功耗原理与流程图
核心目标是:在"需要交互/配置"时提供 Web 管理能力;在"等待触发/执行任务"时尽量进入自动 light sleep 或 deep sleep,并避免"唤醒脚持续高电平导致刚睡就醒"的循环。
补充说明:
- "维持 MQTT 在线"期间:启用
CONFIG_PM_ENABLE + CONFIG_FREERTOS_USE_TICKLESS_IDLE,空闲时系统会自动进入 light sleep;WiFi 使用WIFI_PS_MAX_MODEM降低维持连接功耗。 - "准备 deep sleep"前:会对关键 IO 做
gpio_hold_en + gpio_deep_sleep_hold_en,确保 5V KEY/WS2812 数据线在睡眠中保持稳定电平,降低漏电与误触发风险。 - “未完成配置"时:若 MQTT 未配置,管理窗口超时后不会盲目进入"正常工作态”,而是进入 deep sleep 并用定时器周期性唤醒再次开放管理窗口(避免长期常亮 AP/STA 耗电,同时保证可维护性)。
WS2812 说明
- 双 IO:配置里同时保留
gpio_ws0/gpio_ws1,运行时若当前gpio_ws初始化失败,会自动回退到另一路并写回 NVS。 - 上下堆叠(双 IO 同时使用):约定
gpio_ws0为"向上堆叠"数据线、gpio_ws1为"向下堆叠"数据线;通过stack.up/stack.down配置两侧各有多少"盒子段",MQTT 点灯可用dir + box + grid精确寻址(见下方 MQTT 示例)。- box 编号约定:默认
box=1表示离本机最近的盒子段,box=N表示最远;如需要反向,可设置stack.up_reverse/stack.down_reverse。
- box 编号约定:默认
- 亮度限制:通过
CONFIG_MAGICBOX_WS2812_MAX_BRIGHTNESS对 RGB 线性缩放,默认 64/255。 - 电源预算限亮(可选):通过
ws2812.power_budget_ma+ws2812.max_on_leds估算并进一步降低亮度上限(避免堆叠/多灯场景超出 5V 供电能力)。 - 测试效果:
POST /api/light支持effect:{"grid":1,"color":"#00FF00","duration":5,"effect":"static"}{"grid":1,"color":"#00FF00","duration":10,"effect":"breathe"}{"grid":1,"color":"#00FF00","duration":10,"effect":"blink","period":800}
注意事项
httpd:路由较多时需要提高max_uri_handlers,页面较大时需要提高 httpd 任务栈;本项目已在main/web_server.c做了对应配置。- Deep sleep 唤醒:当前使用
GPIOdeep sleep wake(ESP32-C3),要求唤醒 GPIO 属于支持 deep sleep wake 的引脚(RTC domain 供电的 pad);若唤醒脚长期为高电平可能造成"刚睡就醒"的循环。 - 唤醒脚高电平:本项目在进入 deep sleep 前会先进入 light sleep 定时轮询,等待唤醒脚变低后再 deep sleep(默认 300ms 轮询),避免"刚睡就醒"的重启循环。
- 自动 light sleep(维持 MQTT 在线时的低功耗):已启用 ESP-IDF 电源管理(
CONFIG_PM_ENABLE)+ FreeRTOS tickless idle(CONFIG_FREERTOS_USE_TICKLESS_IDLE),并在启动时通过esp_pm_configure(..., light_sleep_enable=true)开启"空闲自动 light sleep"(见main/power_management.c)。同时 action mode 使用WIFI_PS_MAX_MODEM以降低 WiFi 维持连接的功耗。
代码入口
main/app_main.cmain/magicbox_config.c(NVS 配置)main/wifi_manager.c(STA/AP 管理)main/web_server.c(httpd)main/mdns_service.c(mDNS)
待优化(下一步)
- MQTT(已具备 QoS1/LWT/去重/重连退避/retained 指令清理/
mqtt_last_id持久化去重):离线队列策略进一步完善(建议统一使用数字id)、在线状态上报扩展(按需增加运行信息/指标) - WS2812(已具备 双 IO 自动回退/上下堆叠寻址/动画/亮度限制/电源预算限亮/box 反向映射):更丰富动画(多灯/分组/场景)、更明确的"定位策略"(例如统一 box 编号与设备在堆叠中的角色约定)
- 低功耗(已具备 WiFi 停止+deinit、GPIO hold+sleep 配置、部分电源域关断):功耗实测与 <100uA 达标优化、唤醒脚长期高电平防抖/策略、更多外设按需关断与验证
固件开源地址:https://gitcode.com/zhangerhao/magicBoxFirmware