Skip to content

代码修改规范 ​

本文面向 FastBee-Arduino 固件、Web 控制台和测试脚本的维护者。目标是减少“修好一处又破坏另一处”的回归,保证各芯片发布环境和运行时功能开关长期稳定。

修改前影响分析 ​

调用链检查 ​

修改任何函数、配置结构或 API 前,先搜索所有调用点:

text
1. 搜索函数名、配置字段、API 路径或宏名。
2. 检查调用方是否依赖返回值、副作用、状态变化或错误码。
3. 判断是否需要同步修改测试、默认配置、Web UI、文档和版本能力接口。

例如修改 NetworkManager::startAPMode() 时,要同时看 initialize()、attemptReconnect()、handle()、ProtocolManager、WiFiManager 和 Web 网络状态页,避免 WiFi 模式切换影响 MQTT 状态机或配网页面。

状态机评估 ​

涉及网络、MQTT、OTA、外设执行、认证或配置保存时,必须列出修改前后的关键状态流。状态机改动不要只看“成功路径”,还要覆盖连接中、失败、超时、恢复、低内存和重启后的状态。

text
修改前:STA -> AP+STA -> STA -> AP+STA(可能震荡)
修改后:STA -> AP(终止重试并保留配网入口)
同步影响:自动重连、MQTT 断开、仪表盘状态、日志告警

跨模块依赖 ​

模块关系关注点
NetworkManager ↔ WiFiManagerWiFi 模式、STA/AP 状态、重连策略
NetworkManager → ProtocolManager网络就绪后 MQTT/Modbus 初始化和恢复
ProtocolManager → Web/APIMQTT/Modbus 状态、配置保存、错误码
HealthMonitor → 网络/Web/SSE低内存降级、连接清理、日志节流
WebConfigManager → 所有模块REST API 路由、认证、配置读写

多芯片兼容 ​

芯片约束
ESP324MB 环境空间紧张,串口默认 UART0
ESP32-S3PSRAM 可缓解大对象分配,但 RMT/红外等驱动需单独验证
ESP32-C34MB 无 PSRAM,重点检查内部 DRAM、分区和库兼容性
ESP32-C64MB/8MB正式环境均无PSRAM,重点检查 GPIO/UART 保留引脚和库兼容性

凡是涉及内存分配、任务栈、库依赖、串口、RMT、USB-CDC、PSRAM 或 lib_ignore 的修改,都必须跑对应芯片环境编译。

修改中编码约束 ​

防御性编码 ​

  • 状态判断要覆盖中间态,例如 connecting、disconnecting、failed、low-memory。
  • 外部输入、JSON 字段、配置数组和引脚列表都要做边界校验。
  • 高频路径避免临时 String 拼接、大对象 JSON 和频繁 new/delete。
cpp
if (currentStatus != WL_DISCONNECTED) {
    WiFi.disconnect(false);
    delay(100);
}

资源清理 ​

  • WiFi 模式切换前后确认是否需要 WiFi.disconnect() 和重连任务停止。
  • new、malloc、文件句柄、任务、定时器和回调注册必须有释放或注销路径。
  • 优先使用 RAII、静态池、预分配缓存和明确的失败返回。

日志分级 ​

cpp
static unsigned long lastLog = 0;
if (millis() - lastLog > 30000) {
    lastLog = millis();
    Serial.printf("[MODULE] Status info\n");
}

LOG_ERROR("NetworkManager: Failed to start AP mode");
  • 高频路径使用节流日志。
  • 一次性事件用 INFO。
  • 错误和异常用 ERROR/WARN,并保留足够上下文。
  • 生产构建默认保持 FASTBEE_STRIP_INFO_LOGS=1、FASTBEE_DEBUG_LOG=0。

并发与时序临界路径 ​

以下规则源自 2026-08-10 Web 访问慢/设备间歇复位事故的复盘,违反任一条都可能引发整机复位或首屏卡顿回归:

  • 单总线传感器物理读取必须经 SensorDriver 收口:DHT/DS18B20/OneWire 是时序敏感协议,驱动库会关全 CPU 中断(InterruptLock)。并发读同一传感器会互相破坏总线时序,expectPulse 超时累计关中断数秒,触发 Interrupt WDT panic 整机复位。SensorDriver 已内置总线互斥锁(SensorBusLock)串行化所有物理读取,业务代码禁止绕过它直接调 DHT/OneWire 库。
  • AsyncTCP 服务任务上下文禁止 delay 轮询:在请求处理路径里 delay 等待资源(如限流槽位)会阻塞在途响应的发送与 onDisconnect 释放,资源永远等不到释放,实测退化为“卡死全部连接再拒绝”(13s 慢请求)。正确组合:立即拒绝(503)+ 前端快速退避重试。
  • 网络准入核对内部8-bit DRAM:使用 MemoryBudget::dram8Free()/dram8Largest()(INTERNAL与8BIT组合能力)。仅8BIT可能包括PSRAM;总heap不能替代内部预算,也不能承诺各设备固定相差28KB。
  • 限流/门控参数修改必须同步前端退避:服务端拒绝策略与前端重试退避是一个整体,单独改一侧都会放大用户感知卡顿(对应回归测试:test/test_static_concurrency.cpp)。

危险 API 副作用登记表 ​

以下 API 有隐式全局状态副作用,调用方必须包在 当前网络模式保护与恢复机制作用域内,或显式恢复原状态并补测试锁定:

API副作用必须的善后锁定测试
WiFi.scanNetworks()内部 enableSTA(true) 把纯 AP(mode=2) 切成 APSTA(mode=3),扫描后不自动恢复作用域结束恢复 WIFI_MODE_AP,否则 STA 残留抽干 DRAM 跌破 tcp_accept 8KB 门控 → AP Web 间歇全拒test_source_ap_probe_prescan_fast_fail
WiFi.begin()初始化 STA 驱动 + lwIP netif,失败断开后 lwIP 缓冲卡滞不回收(仅下次重连复用)不可见候选按有界预扫描/重试策略处理,失败后恢复AP并核对资源;不能断言所有扫描不到的SSID均禁止连接同上

类型与接口安全 ​

  • 跨抽象层调用时确认接口是否属于基类,必要时使用显式转换并检查空指针。
  • API 响应字段新增、删除或语义变化时,同步 Web UI、测试矩阵和文档。
  • 配置结构新增字段时,同步默认配置、迁移逻辑、导入导出和恢复出厂设置。

前端样式 ​

  • 优先复用 web-src/css/main.css 中的 .fb-* 组件类和设计令牌。
  • 页面内样式只用于当前页面确实需要的局部覆盖。
  • 修改前端后必须验证 gzip 产物体积和静态资源完整性。

修改后验证矩阵 ​

统一入口是 scripts/test-all.ps1。按改动风险选择检查项,影响共享模块、配置、网络、协议或 Web/API 时不要只跑单环境。

检查命令覆盖内容
静态检查scripts/test-all.ps1 -Checks staticUTF-8、测试注册、API 矩阵、默认配置、Web 静态资源等
native 单元测试scripts/test-all.ps1 -Checks nativehost 侧 C++ 单元测试
多芯片编译scripts/test-all.ps1 -Checks buildESP32、C3、C6、S3 的发布环境
发布产物scripts/test-all.ps1 -Checks artifacts合并固件、LittleFS、manifest
设备冒烟scripts/test-all.ps1 -Checks device-smoke -BaseUrl http://<设备IP> -DeviceProfile unified登录、系统、网络、协议、外设、执行、版本能力
设备浸泡scripts/test-all.ps1 -Checks device-soak -BaseUrl http://<设备IP> -DeviceProfile unified -SoakRounds 100API 循环、内存趋势、认证稳定性和响应耗时

常用本地命令:

powershell
# 快速提交前检查
powershell -ExecutionPolicy Bypass -Command ".\scripts\test-all.ps1 -Checks static,build"

# 完整本地矩阵,不访问真实设备
powershell -ExecutionPolicy Bypass -Command ".\scripts\test-all.ps1 -Checks static,native,build,artifacts"

# 单个 native 测试
npm run test:native

高风险修改清单 ​

类型风险必查项
WiFi 模式切换栈溢出、状态震荡、配网入口丢失禁止无约束 AP+STA 震荡;模式切换前清理状态
MQTT 连接管理断网时无意义重试、内存消耗、阻塞主循环isNetworkConnected() 门控、退避重连、低内存暂停
内存分配堆碎片、最大连续块不足、任务栈溢出大对象优先 PSRAM、低内存降级、避免高频分配
传感器驱动/单总线访问并发读破坏时序 → 关中断超时 → Interrupt WDT 整机复位只走 SensorDriver(内置总线互斥锁);禁止业务层直连 DHT/OneWire 库;回归测试 test/test_sensor_driver.cpp
Web 静态限流/门控delay 等待退化为连接卡死;参数回退引发 503 风暴立即拒绝 + 前端退避承接;静态租约回收超时与任务WDT分别核对,12s静态租约不是任务WDT;回归测试 test/test_static_concurrency.cpp
platformio.ini 依赖未用库被编译、Flash 膨胀、芯片不兼容检查 lib_deps、lib_ignore、宏和多芯片编译
Web/API 字段前端显示异常、测试矩阵失配、旧配置不兼容同步 UI、默认配置、导入导出、API 测试
OTA/文件系统断电损坏、分区不匹配、恢复失败断电恢复、校验失败、旧固件回退路径

回归测试规范 ​

每次修复 Bug 都应补对应测试。测试文件按模块组织,并按当前主机/Native入口及 scripts/validate-test-coverage.js 要求登记。

稳定性类修复推荐双层守护模式(2026-08-10 事故后固化):

  1. 源码锁定:readProjectFile 读源文件断言关键常量/结构存在,且旧的危险写法显式断言不存在(防回潮);
  2. 行为验证:优先执行真实解析器、调度器、序列化或驱动代码,以mock替换外部依赖。避免复制实现后只验证镜像,关键失败与退出路径须覆盖。

参考实现:test/test_static_concurrency.cpp(限流器)、test/test_sensor_driver.cpp(总线互斥)。

Bug 类型测试建议
逻辑错误行为单元测试或源码回归测试
状态机错误状态转换模拟测试
内存问题堆阈值、低内存保护或长稳测试
配置错误默认配置、导入导出、非法字段测试
多模块协作E2E 场景测试
性能退化性能基准或 soak 指标

新增设备 API 时,必须同步 scripts/device-api-test-matrix.json,本地回归后在获准目标上安排对应环境smoke,缺设备时保留待验证(当前发布固件使用 unified 断言集)。

Git 提交要求 ​

  • 一个提交解决一个问题,修复和对应测试放在同一个提交中。
  • 提交信息使用 Conventional Commits,例如 fix(network): STA 失败后回退纯 AP 模式。
  • 提交正文写清楚根因、改动点、验证命令和影响范围。
  • 不把无关格式化、文档同步和功能修复混在一个提交里。

AI 辅助开发注意事项 ​

  • 提需求时优先给出现象、日志、期望行为和复现步骤。
  • 审核修改时检查调用点、状态机、日志格式、测试和文档是否同步。
  • AI 不能替代硬件验证;WiFi、MQTT、内存趋势、多设备并发和具体传感器兼容性仍需真机确认。

蜂信物联 | fastbee.cn