ESP32智能插座调试软件功能测试:从用例设计到自动化回归实战

📅 发布时间:2026/9/8 14:37:33
ESP32智能插座调试软件功能测试:从用例设计到自动化回归实战 做智能插座开发硬件焊接好只是第一步真正折磨人的是软件联调阶段。ESP32 智能插座的功能测试重点往往不在单片机端而在那套配套的调试软件上。我最近刚完成一个基于 ESP32 的智能插座项目从配网到继电器控制再到电量计量整个调试软件的功能测试跑了好几轮中间踩了不少坑。这篇就把调试软件的设计思路、测试用例规划、实测问题定位和自动化回归方案一次性说清楚希望对正在做同类项目的朋友有参考价值。1. 项目背景与调试目标ESP32 智能插座软硬件联调到底要验证什么1.1 硬件组成与调试软件的定位先明确一下项目背景。我做的这个 ESP32 智能插座硬件上并不复杂主控是 ESP32-WROOM-32 模组电源部分用 HLK-PM01 AC-DC 模块继电器选的是松乐 SRD-03VDC-SL-C电流电压采样用了互感器加运放电路另外还有一颗 DHT11 做温度采集一个 LED 指示灯和一个轻触按键。整套硬件成本控制在 40 元以内非常适合小批量验证。但硬件简单不等于联调简单。ESP32 智能插座真正复杂的是软件层WiFi 配网、MQTT 连接、继电器控制、ADC 电量采样、定时任务、OTA 升级再加上掉线重连、异常恢复这些逻辑全都堆在一个固件里。如果没有一套专门的调试软件来辅助验证光靠串口打印来测一个用例一个用例手工敲命令效率会低到让人崩溃。所以我在项目启动时就确定了调试软件的定位它不是给终端用户用的 App而是给开发者自己用的瑞士军刀。它需要做到三件事批量触发设备端功能比如模拟 App 下发控制指令、模拟断网、模拟按键长按恢复出厂。实时观察设备端状态比如当前 WiFi RSSI、MQTT 连接状态、继电器开关状态、AC 采样频率和电压电流值。记录并回放测试日志方便定位偶发问题。这套调试软件我选择了PC 上位机 网页配网工具的组合模式而不是一上来就做手机 App。原因是开发周期短而且 PC 上跑自动化脚本方便。后面功能测试也直接基于这套调试软件展开。1.2 功能测试的边界划分就我个人的项目经验来看ESP32 智能插座的调试软件功能测试至少要覆盖以下四层第一层是通信链路层。调试软件要通过 WiFi 或串口与设备通信首先要验证通信链路是否稳定包括 TCP/MQTT 长连接能否建立、心跳包是否按预期发送、通信数据帧的格式是否正确。这一层如果出问题后面所有测试都是白搭。第二层是业务指令层。也就是继电器开/关、倒计时、定时任务、电量查询等控制指令的下发与执行。这一层重点验证指令的交互流程和返回码。第三层是状态同步层。设备端的状态变化能不能实时同步到调试软件上比如手动按键开灯后调试软件上的状态显示是否同步更新。这一层直接关系到用户体验也最容易出现不一致的问题。第四层是异常恢复层。断网重连、重启后状态恢复、 WiFi 密码错误、MQTT 服务器不可用等异常场景都要通过调试软件模拟出来并验证设备的自恢复能力。明确了这四层边界功能测试才有针对性。接下来我们看调试软件本身是怎么设计的因为测试用例的写法跟软件架构直接相关。2. 调试软件的能力划分上位机、配网工具与设备端日志系统的配合2.1 为什么不自研全套上位机很多人一听到调试软件就认为要做一个完整的图形界面程序界面上面板一大堆按钮密密麻麻。但我的经验是调试软件的第一原则是轻量、快速、可脚本化。我见过不少工程师花了两三周写了一个 Qt 上位机结果真正调试设备时发现很多电路参数需要临时改界面改起来又慢最后又回到串口助手加命令行。真正高效的 ESP32 智能插座调试方案是把它拆成三部分各管各的组件技术方案职责设备端调试日志系统ESP32 内部日志 串口输出记录日志、可动态调整日志级别网页配网工具ESP32 内置 WebServer 手机浏览器ESPTouch 配网失败时的备用配网方案PC 上位机/脚本Python Paho-MQTT PySerial批量控制、自动化测试、数据采集我在这个项目中的做法是设备端写了两套服务一个是 MQTT 客户端用于接收业务指令另一个是调试服务器作用在调试状态下才开启监听自定义的 TCP 端口可以下发调试指令、读取内部状态、触发模拟异常。PC 端则是一个 Python 脚本通过 MQTT 发控制消息通过 TCP 读设备内部状态通过串口读日志。三者互相配合功能测试时基本上一个脚本就能跑完一个用例。2.2 设备端调试协议的设计思路调试软件与设备通信必须约定协议。我用的协议并不复杂基于 JSON 格式类型字段区分请求和响应。例如控制继电器{cmd:relay_ctrl,ch:1,state:1,req_id:1024}设备端返回{ret:0,state:1,req_id:1024}关键是要带上req_id这个字段在功能测试中很重要。因为异步通信环境下调试软件发出请求后无法确定哪条响应对应哪条请求有了req_id就可以把请求和响应配对测试脚本做起断言来就方便多了。另外我还在协议里加了一个dump命令设备收到后会把当前完整状态以 JSON 形式返回包含 WiFi RSSI、IP、MQTT 状态、各继电器状态、ADC 最近 10 次的采样值、可用堆内存等。这个命令在功能测试里帮了大忙断言状态异常时我直接拉一份完整状态几乎不需要猜。2.3 日志系统的分级与闭环调试软件能不能高效工作日志系统是关键。ESP32 的日志机制本身就支持 verbose/debug/info/warn/error 五级但默认只输出到串口。在功能测试中我强烈建议把日志也通过调试协议远程拉取而不是每次都要插 USB 线。我实现了一个简单的时间戳环形缓冲区日志写到内存的同时异步发送到 PC 端调试脚本。当测试脚本收到错误响应时可以主动向设备发起一次日志转储请求把最近 200 条日志拉取下来打包到测试报告中。这样就不需要一直开着串口自动化测试也能跑。日志系统还有一个细节容易被忽略即设备重启时日志缓冲区会清零。为了追踪偶发的重启问题我把日志写入了 ESP32 的 NVS 中的一个循环块这样设备重启后 PC 端依然可以通过调试协议拿到复位前的最后一段日志。这个功能在后面的异常排查中帮我定位了一个非常隐蔽的 Timer 溢出问题。3. 功能测试用例设计与执行矩阵配网、控制、计量、OTA 一条龙3.1 配网流程测试用例配网是智能插座第一个功能入口测试优先级最高。实际测试时我把配网分成三种模式来覆盖ESP-Touch 一键配网、Web 配网AP 模式、以及蓝牙配网BLE。虽然最终发布版只保留了 ESP-Touch 和 Web 配网但调试软件中都做了支持因为要对比数据。每个配网模式设计的核心测试用例如下用例编号场景测试步骤预期结果NET-01首次上电配网设备上电后进入配网模式使用调试软件发送配网指令配网成功设备获取到 IP状态上报NET-02配网超时设备进入配网模式后 5 分钟无操作指示灯熄灭设备自动进入低功耗模式NET-03错误密码使用错误 WiFi 密码配网提示配网失败设备不进入连接状态可再次配网NET-04配网成功但断网配网成功后手动断开路由器 WiFi设备检测到断网进入重连状态恢复后自动重连这些用例看起来常规但执行时容易在异常分支上出问题。比如 NET-02 我在写用例时只验证了超时后的低功耗没验证超时后再次配网是否正常结果测试时真的发现设备在超时状态后无法重新进入配网模式原因是状态机里没有清理配网超时标记。这类边界问题最喜欢藏在这种用例没覆盖到的地方。3.2 控制指令与状态同步测试控制指令测试是调试软件的核心功能测试内容。我把测试对象分为三类单继电器控制、双联继电器联动控制、以及继电器控制状态回传。单继电器控制测试最简单脚本通过 MQTT 发布一条relay_ctrl指令然后读取设备回传状态断言继电器实际引脚电平与目标状态一致。这里要注意不能只断言ret 0否则很可能设备端发了一条响应但继电器根本没动作。双联继电器联动测试稍微复杂一点。我设计了一个用例同时给插座的两个通道下发相反状态通道 1 开、通道 2 关然后检查两个通道的反馈是否都正确。在首次测试时发现通道 2 状态正确但响应消息中通道 1 的状态始终是上一次的值后来定位发现是调试协议中状态缓存没有在通道切换时清空实则是因为使用了旧版本结构体通道状态存储偏移量写错了。这类问题只有测试多了才能暴露。3.3 计量精度与 ADC 采样测试调试软件的功能测试如果只关注开关控制那就太小看智能插座了。我用了一个 60W 白炽灯和一台电风扇作为负载分别测量电压电流和功率将 ESP32 ADC 采样换算结果与 Fluke 万用表读数对比。电压采样用 ZMPT101B 电压互感器ADC 采样 1000 次取平均。电流采样用电流互感器加运放整流采样窗口覆盖完整工频周期。功率因数本项目暂未做固定按 1.0 计算。实测结果如下表负载万用表电流设备测量电流误差60W 白炽灯0.273A0.281A2.9%60W 白炽灯 风扇低档0.402A0.418A3.9%只开风扇高档0.335A0.349A4.1%误差整体偏大在低电流段问题更明显。进一步分析发现电流互感器二次侧运放的整流二极管在小信号时非线性是误差拉高的主要原因后来通过软件补偿非线性区间把误差压到了 2% 以内。这个用例如果没有调试软件的数据导出功能很难定位是硬件问题还是软件运算问题。3.4 OTA 升级功能测试OTA 是智能插座很重要的一个功能因为出货后固件升级全靠它。我在调试软件中集成了一个模拟 OTA Server功能测试时把固件分成三类正常全量包、非法签名包、以及截断包。测试步骤分两层先通过调试软件下发 OTA 开始指令设备端将固件分片写入 flash。固件写完后设备端做校验然后重启检查新的 firmware 版本号是否一致。核心关注点有三个升级过程中掉电、升级包校验失败、以及升级成功后启动失败的回滚。ESP32 的 ota 机制自带两个 app 分区如果新固件不行会自动回滚到旧固件但前提是分区表配置正确且新版固件在规定时间内完成启动并向调试软件上报 ready 事件。这个在测试时要特别注意否则明明 OTA 写进去了因为启动超时被回滚表面看起来像升级失败。3.5 定时任务与倒计时测试定时任务测试主要是验证 RTC 时间同步、时区处理和触发逻辑。我在调试软件的测试脚本里通过 MQTT 指令设置当前时间和定时任务时间到了之后检查继电器是否动作。最容易遗漏的坑是时区。ESP32 自带的settimezone接口在编译时如果没启用 POSIX 时区字符串设置会静默失败。我测试时设置了Asia/Shanghai设备也显示同步到了 NTP但实际定时任务总偏差 8 小时。检查后才发现是CONFIG_LIB_POSIX_TZ_STRINGS这个宏没有打开改为CST-8才真正生效。倒计时测试相对简单关键是用系统时间驱动而非用delay()。我的一个早期版本在倒计时里用了vTaskDelay设备一旦有阻塞任务就会延迟触发后来统一改成了绝对时间戳判断问题就解决了。4. 实测中的异常场景与排查链路从现象到根因的完整复盘4.1 复现策略调试软件如何模拟异常场景功能测试不能光测正常路径异常场景才是智能插座稳定性的分水岭。调试软件需要能模拟这些异常场景我在上位机中实现了几个故障注入按钮断网注入直接关闭 WiFi 或者调用设备的esp_wifi_stop()调试指令。MQTT 服务器不可用将 MQTT broker 地址修改为无效 IP。继电器负载短路通过调试指令强制继电器以极快频率切换模拟大电流冲击。NVS 掉电写坏模拟在写入 NVS 关键标志期间断电验证设备重启后能自动恢复。这种故障注入能力是普通串口助手做不到的也是我坚持要写专门调试软件的原因。4.2 一次偶发重启的排查过程这里分享一下我在这项目中耗时最久的调试过程设备在继电器切换瞬间偶发重启。现象是手动按下按键开启继电器时约 5% 的概率设备会重启重启后调试软件上看到日志从boot开始打印。由于是偶发一开始根本抓不到头绪怀疑是继电器线圈反电动势影响电源于是在继电器两端加了续流二极管问题依旧。后来我用调试软件的日志转储功能把每次重启前的最后 200 条日志拉出来。连续跑了大约 50 次终于抓到一条关键日志assert failed: gpio_set_level。原来重启前程序正在执行继电器控制函数调用gpio_set_level时传入了无效引脚号。进一步排查发现我的 GPIO 扩展逻辑里有通道号和物理引脚的映射数组通道 2 对应 GPIO 16但初始化函数在某种时序下没有把该引脚模式从输入切换为输出。键切换瞬间读取按键状态的 ADC 任务优先级比控制任务高导致控制任务执行到一半被打断而按键扫描任务恰好复用了引脚初始化函数中的全局变量把引脚模式改成了输入。这种问题单纯靠代码 review 很难发现必须有调试软件提供足够现场数据才能定位。修复方案很简单线程互斥锁保护引脚配置同时在gpio_set_level之前增加模式检查。但这个案例让我养成了一个习惯——所有控制类函数在入口处都做入参合法性检查尤其是引脚号这种低层参数避免野指针或者越界引起不可预期的行为。4.3 MQTT 消息丢失的定位另一个常见的异常场景是 MQTT 消息丢失。智能插座在信号不好的环境里工作MQTT 连接动不动断开重连有时候调试软件明明发了继电器开设备端却没有任何反应。我第一反应是 QoS 设置问题。因为当时发消息用的是 QoS 0失败不重发。将消息级别提升到 QoS 1 后消息确实不再丢但设备端还是偶发不响应。进一步排查发现问题不在网络传输而在于设备端 MQTT 回调函数里直接调用了relay_ctrl函数导致在 LiveQueue 回调上下文里执行耗时操作阻塞了 MQTT 客户端底层处理后续消息全部积压没有处理。修复方式是把 MQTT 回调改成只往 FreeRTOS 队列里投递事件由专门的任务处理指令。这个改动后MQTT 消息丢失的问题彻底消失。功能测试的结论是调试软件不能只测应用层指令还要关注协议栈与任务调度的交互测试用例里应加上高频连续指令、大消息体这类压力场景。4.4 调试软件自身的问题串口数据粘包在做功能测试时除了设备端的 bug调试软件自身也会出问题。最典型的是串口读取时粘包。ESP32 的日志输出不是每行独立 flush 的小数据块可能被合并成一个大 TCP/IP 包发出。调试软件如果用简单按行读取的方式解析串口数据很容易出现一行被截断、两行合并的情况。我在早期版本中基于串口缓存取数据结果测试用例里总有个别数据解析不了就是这个原因。后来我在设备端日志协议中加入了帧头帧尾PC 端通过滑动窗口解析完整帧彻底解决了粘包问题。这也提醒我调试软件本身也是软件也必须经过严格的功能测试不能想当然认为工具代码不会有 bug。5. 自动化回归让调试软件自身可被持续验证5.1 从手工测试到半自动脚本的演进刚开始做功能测试时我完全是手工操作打开调试软件、点击配网、点击控制、查看日志用例多的时候一天下来人非常疲惫而且容易漏测。测试执行到第三轮时我已经发现同一个用例在不同时间跑结果不一样很可能是因为某次手工操作时点击顺序不对。于是我用 Python 写了一个简单的测试框架核心只有三块指令发送模块通过 MQTT 或 WebSocket 向设备发送指令等待响应。状态读取模块通过调试协议读取设备当前状态与预期值比对。结果记录模块把每个用例的执行结果写入 JSON 和 Markdown 报告方便回溯。这算是一个最小可用的半自动化测试环境。写用例时只需要继承一个 BaseCase在run()方法里连续调用上述模块即可。5.2 测试用例断言的关键点自动化测试最怕的就是断言写得太粗糙。我有几个亲测有效的心得第一不要只看返回码。比如控制指令返回ret:0只代表设备端收到消息并执行了协议解析并不代表继电器正确动作。还需要读取实际引脚电平或电流采样值来确认物理层面的结果。第二异步等待要有超时机制。设备做 OTA 升级时整个流程可能持续几十秒。如果用固定 sleep测试用例既慢又不可靠最终都会因为偶发超时而失败。我用了轮询加整体超时的方式每 200ms 读取一次状态直到出现预期状态或者超过 30 秒才判定用例是否通过。第三测试用例之间必须隔离。我在跑自动化回归时发现前一个用例设置的定时任务或继电器状态会影响后一个用例的结果。后来在每个用例的setup()里强制设备先回到出厂默认状态再执行正式测试。刚开始觉得费时但这样做才能保证用例的独立性。5.3 回归测试的执行效率与稳定性当用例数量超过 30 个以后回归一次的时间成为瓶颈。我统计过跑一遍完整智能插座功能测试用例需要大约 25 分钟其中 OTA 完全测试占了近一半时间因为升级、重启、回滚都需要等待。为了控制回归成本我把用例按优先级分成三档优先级用例范围回归时机P0配网、继电器控制、状态同步、异常重启恢复每次代码提交后执行P1计量精度、定时任务、断网重连每周执行P2OTA 升级、多负载压力、长时间稳定性≥24h版本发布前执行这样既保证了基本功能随时可用又不至于让每个小改动都消耗大量测试资源。还有一个稳定性细节自动化测试平台最好用双路由器模拟弱网环境。直接用一台路由器做信号太强弱网场景很难复现。我的做法是在主路由器之外放了一个支持不限速的便携路由器再用金属屏蔽盒适度衰减信号把 RSSI 控制在 -75dBm 到 -85dBm 之间这个区间跑出来的断线重连测试才有参考价值。5.4 调试软件与 CI 的集成如果团队足够大调试软件应该接入 CI 流程。我在这个项目里也做了轻量级验证用 Jenkins 的 pipeline 定时任务每天晚上自动跑一遍 P0 用例并把报告发送到企业 IM。这里有一个需要提醒的地方ESP32 设备通过 USB 转串口连接到测试 PC 时PC 每次只能与一个设备实例通信。如果同时测多台设备就需要用 USB Hub 扩展多路串口Python 脚本里按设备 ID 分发指令。我一开始只接了单台设备后来扩到 4 台时发现日志里有不同设备的串口数据混在一起原因是各串口的读取线程没有做数据隔离。这些都是自动化过程中值得注意的细节点。6. 后续可扩展的测试能力与个人建议6.1 把调试软件进阶为量产产测工具一个项目的调试软件如果只服务于研发阶段生命周期其实比较短。但 ESP32 智能插座的调试软件完全可以扩展成量产产测工具因为它已经包括了通信链路建立、指令交互、状态读取、日志分析这些全部基础能力。量产产测相比研发调试多了几项硬性要求测试结果要自动存档到数据库生成序列号对应的测试报告。测试项要剔除人工干预一个测试工位最好一键启动、自动执行、自动判定 P/F。要支持多工位并发每工位一台设备一个串口互相独立。我在量产阶段把之前写的 Python 测试框架扩展成了多进程模式每个工位用一个独立进程跑测试套件测试报告写入 MongoDB 并按日期分表效果很理想。所以建议一开始写调试软件时就不要把功能写死保留命令行调用和结果导出接口后面扩展产测会省很多事。6.2 设备端日志策略的经验最后分享一点我在日志策略上的个人体会。调试软件功能测试依赖设备端日志但日志打太多会影响实时性打太少又会导致问题无法定位。我最终的平衡点是正常运行阶段只打 info 级别以上日志。调试模式下全部开启 debug 级别。关键状态变化如继电器动作、WiFi 断开、OTA 启动使用专门的 event 日志通道不受日志级别开关影响必须记录并携带时间戳。日志环形缓冲区按线程优先级区分控制任务的日志预留足够空间防止被高频率传感器刷掉。这些策略听起来简单但开发初期我根本没当回事直到排查问题需要日志时才发现打印被淹没或者被截断才回头优化。如果一开始就规划好后续测试的效率会高很多。6.3 建议的开发顺序假如你正要开始做类似项目我建议按以下顺序推进调试软件与功能测试先把串口日志和状态导出功能做扎实这是所有调试的基础。实现调试协议中的dump和fault_inject命令即状态导出和故障注入。用 Python 或你熟悉的脚本语言搭最小测试框架只覆盖 P0 用例。跑通第一轮回归再根据结果补测试用例。最后做 OTA、产测、多设备并发这些高级能力。按照这个顺序即使前期调试软件功能不完善也不影响基本的功能测试。反过来如果一开始就想把调试软件做到完美反而会拖延整个项目进度。做 ESP32 智能插座调试软件功能测试本质上是一个不断设计-实验-发现问题-优化工具-再实验的循环。工具本身会随着测试深入而越来越强设备固件也在不断迭代中变得更稳健。希望这篇分享能帮你在开始前避开我走过的弯路。如果你也在做类似的智能设备调试项目欢迎交流你的测试方案和踩坑经历。