在远程办公成为常态的今天,如何在共享空间中保护会议隐私成为一个实际需求。传统的解决方案如共享日历或简单的门牌存在诸多局限:日历无法覆盖突发会议,门牌需要手动操作,而手机通知又可能被忽略。一个名为 "Over-Engineering a 'Do Not Disturb' Device" 的开源项目提供了一个硬件解决方案,其技术演进路径值得深入分析。
问题背景与技术选型
项目最初的需求很简单:当 MacBook 摄像头开启时,门外设备显示红色 "请勿打扰" 状态;摄像头关闭时显示绿色 "可进入" 状态。作者尝试了多种方案后,最终选择了 ESP32 作为核心控制器,原因在于其内置 Wi-Fi 和蓝牙双模通信能力,以及丰富的 GPIO 接口。
最初的架构采用 HTTP 轮询方式:ESP32 每隔 500ms 向 MacBook 上的 Bun 服务器发送请求,查询摄像头状态。这种方式虽然实现简单,但存在两个核心问题:一是动态 IP 地址导致设备需要频繁重新配置,二是轮询机制带来不必要的功耗浪费。
从 HTTP 轮询到 BLE 推送的架构演进
HTTP 轮询的局限性
在初始设计中,ESP32 通过 Wi-Fi 连接,定期向http://192.168.0.5:1337发送 GET 请求。这种方式的功耗相当可观:ESP32 在 Wi-Fi 活动模式下功耗可达 240mA,即使采用轻睡眠模式,每 500ms 唤醒一次的功耗也超过 50mA。对于 USB 供电的设备来说,这或许可以接受,但对于电池供电的场景则不可持续。
BLE 推送的优势
项目演进到第二阶段时,作者将通信协议从 HTTP 切换到了 BLE(蓝牙低功耗)。BLE 的核心优势在于其极低的功耗特性:在连接间隔为 100ms 的情况下,平均功耗仅为 1-2mA,相比 Wi-Fi 节省了 90% 以上的功耗。
更重要的是,BLE 支持服务器主动推送(Server Push)模式。当摄像头状态发生变化时,MacBook 作为 BLE 服务器可以立即向 ESP32 客户端发送通知,无需等待轮询。这不仅降低了延迟,还进一步减少了不必要的通信开销。
mDNS 解决动态 IP 问题
在局域网内,作者采用了 mDNS(多播 DNS)技术来解决动态 IP 地址问题。通过将 MacBook 注册为Apoorvs-MacBook-Pro.local,ESP32 可以通过域名而非 IP 地址进行连接,避免了因路由器 DHCP 重新分配 IP 而导致的连接中断。
自定义二进制协议设计
协议设计动机
作者在设计过程中发现,标准的 JSON 或 Protocol Buffers 格式对于这个简单场景来说过于重量级。一个简单的状态更新{"status": "on", "timestamp": 1736294400}需要数十字节,而实际上只需要传达几个比特的信息。
DoorFrame Protocol v1
为此,作者设计了名为 "DoorFrame Protocol" 的自定义二进制协议。协议的核心思想是用最少的字节传达最多的信息:
握手协议(2 字节):
0xDF:协议魔数(DoorFrame)0x01:版本号
状态命令(1 字节):
0xC0:摄像头关闭(C 代表 Camera)0xC1:摄像头开启
时间编码(2 字节):
- 小时字节:
0x7H(H 为小时数,24 小时制) - 分钟字节:
0x8M(M 为 5 分钟间隔,如0x86表示 30 分钟)
这种设计将原本需要 20-30 字节的 JSON 数据压缩到 1-3 字节,不仅减少了传输开销,还降低了 ESP32 的解析复杂度。
协议扩展性考虑
虽然当前协议非常简单,但作者在设计时考虑了扩展性。协议头部预留了版本字段,未来可以向后兼容。同时,命令字节的高 4 位用于标识命令类型,低 4 位用于具体参数,这种设计允许最多 16 种命令类型,每种命令最多 16 个参数值。
低功耗设计策略
ESP32 功耗模式选择
ESP32 提供了多种功耗模式,根据项目需求选择合适的模式至关重要:
- 活动模式(Active Mode):240mA,全功能运行
- 调制解调器睡眠模式(Modem-sleep):20-30mA,CPU 运行,Wi-Fi / 蓝牙关闭
- 轻睡眠模式(Light-sleep):0.8mA,CPU 暂停,内存保持
- 深度睡眠模式(Deep-sleep):10μA,仅 RTC 运行
- 休眠模式(Hibernation):2.5μA,最低功耗
对于这个项目,作者采用了轻睡眠模式结合 BLE 事件唤醒的策略。当没有 BLE 通信时,ESP32 进入轻睡眠状态,功耗降至 0.8mA;当 MacBook 发送状态更新时,BLE 中断唤醒 ESP32,更新显示后立即返回睡眠。
功耗优化参数清单
基于实际测试,以下是推荐的功耗优化参数:
-
BLE 连接参数:
- 连接间隔:100-200ms(平衡响应速度与功耗)
- 从机延迟:0(每次连接事件都唤醒)
- 监控超时:2s(连接丢失检测)
-
睡眠策略:
- 无通信超时:5s 后进入轻睡眠
- 显示更新后:立即返回睡眠
- RTC 内存使用:保存连接状态和显示内容
-
显示功耗控制:
- OLED 屏幕亮度:30%(足够室内可见)
- 屏幕刷新率:1Hz(状态稳定时)
- 背光控制:根据环境光自动调节
预期电池寿命计算
假设使用 1000mAh 的锂电池:
- 活动模式(持续):1000mAh ÷ 240mA ≈ 4.2 小时
- BLE 连接模式(平均 2mA):1000mAh ÷ 2mA ≈ 500 小时(约 21 天)
- 轻睡眠模式(0.8mA):1000mAh ÷ 0.8mA ≈ 1250 小时(约 52 天)
实际使用中,设备大部分时间处于轻睡眠状态,偶尔被 BLE 事件唤醒,预计电池寿命可达 30-40 天。
硬件工程与 3D 打印优化
外壳设计挑战
作者从软件工程师转型硬件设计,面临的最大挑战是公差控制。在软件世界中,1 + 1总是等于2;但在 3D 打印中,材料收缩、喷嘴尺寸、层高都会影响最终尺寸。
公差设计参数
经过多次迭代,作者总结出以下公差设计原则:
- 干涉配合:对于需要紧密配合的部件,设计负公差(-0.1mm)
- 滑动配合:对于需要相对运动的部件,设计正公差(+0.2mm)
- 卡扣设计:悬臂梁厚度为 1.2mm,挠度控制在 0.5mm 以内
- 材料收缩补偿:PLA 材料收缩率约 0.2%,设计时按 1.002 倍放大
装配优化清单
- 分件设计:将外壳分为前盖、后盖和内部支架,便于打印和装配
- 定位特征:添加定位柱和定位孔,确保组件对齐
- 螺丝孔设计:M2 螺丝孔设计为 2.4mm,预留 0.4mm 装配间隙
- 线缆管理:设计线槽和固定点,避免内部线缆松动
热管理考虑
虽然 ESP32 功耗不高,但在密闭外壳中仍需考虑散热:
- 外壳顶部设计通风孔
- ESP32 与外壳间预留 1mm 空气间隙
- 避免将电源模块与主控芯片堆叠
软件架构与监控系统
分层架构设计
项目采用清晰的分层架构:
- 硬件抽象层:封装 ESP32 的 GPIO、BLE、显示驱动
- 协议层:实现 DoorFrame Protocol 的编码解码
- 业务逻辑层:处理状态机、功耗管理、错误恢复
- 监控层:记录设备状态、连接质量、电池电压
错误处理策略
- 连接丢失检测:BLE 连接超时 2s 后尝试重连
- 状态同步:重连后立即请求当前状态
- 降级策略:BLE 失败时回退到 HTTP 轮询(如果配置了 Wi-Fi)
- 电池保护:电压低于 3.3V 时进入深度睡眠,防止过放电
监控指标
设备通过 BLE 定期上报以下监控数据:
- 电池电压(12 位 ADC 精度)
- 内部温度(ESP32 内置传感器)
- 连接质量(RSSI 值)
- 运行时间(从启动开始的毫秒数)
部署与维护考虑
生产部署清单
- 固件烧录:使用 PlatformIO 或 Arduino IDE 批量烧录
- 设备配对:首次启动进入配对模式,通过手机 App 配置 Wi-Fi
- 质量控制:每台设备进行功能测试和功耗测试
- 包装设计:防静电包装,包含快速入门指南
OTA 更新策略
虽然当前版本未实现 OTA,但架构预留了扩展空间:
- 双分区设计:ESP32 支持 A/B 分区,实现无缝更新
- 差分更新:仅传输变更部分,减少带宽需求
- 回滚机制:更新失败自动回退到上一版本
- 版本验证:数字签名确保固件完整性
总结与展望
这个 "过度工程" 的项目实际上展示了 IoT 设备开发的完整生命周期:从需求分析、技术选型、架构设计,到功耗优化、硬件工程、生产部署。虽然项目规模不大,但涉及的技术栈相当全面。
关键收获:
- 协议设计:自定义二进制协议在资源受限场景下的优势明显
- 功耗优化:从毫安级到微安级的优化需要系统级思考
- 硬件软件协同:公差控制、热管理等硬件问题直接影响软件设计
- 渐进式演进:从简单的 HTTP 轮询到复杂的 BLE 推送,架构需要支持平滑迁移
未来扩展方向:
- 多设备同步:支持多个状态指示器同步显示
- 环境感知:集成光线传感器、运动传感器,实现更智能的状态判断
- 云集成:将设备状态同步到云端,实现远程监控
- 能源收集:集成太阳能电池板,实现完全无线供电
这个项目最值得借鉴的不是其具体实现,而是其工程思维:在满足核心需求的前提下,不断优化各个技术环节,平衡性能、功耗、成本和可维护性。对于嵌入式开发者来说,这种端到端的思考方式比掌握某个具体技术更为重要。
资料来源
- Over-Engineering a "Do Not Disturb" Device - 原始项目博客
- ESP32 Sleep Modes & Power Consumption - ESP32 功耗分析
- Custom Network Protocol Development - 自定义协议设计指南