Code Change Guidelines
Code Change Guidelines
This document is for maintainers of FastBee-Arduino firmware, Web console and test scripts. The goal is to reduce "fix one thing, break another" regressions and ensure long-term stability across Lite, Standard and Full editions on different chips.
Pre-Change Impact Analysis
Call Chain Check
Before modifying any function, configuration structure or API, search all call sites:
1. Search for function name, config field, API path or macro name.
2. Check if callers depend on return values, side effects, state changes or error codes.
3. Determine whether tests, default config, Web UI, docs and edition capability interfaces need synchronized updates.For example, when modifying NetworkManager::startAPMode(), also check initialize(), attemptReconnect(), handle(), ProtocolManager, WiFiManager and the Web network status page to avoid WiFi mode switching affecting MQTT state machine or provisioning page.
State Machine Assessment
When changes involve network, MQTT, OTA, peripheral execution, authentication or config saving, you must list key state flows before and after the change. Do not only check the "happy path" for state machine changes - also cover connecting, failed, timeout, recovery, low-memory and post-reboot states.
Before: STA -> AP+STA -> STA -> AP+STA (may oscillate)
After: STA -> AP (terminate retry, keep provisioning entry)
Sync Impact: auto-reconnect, MQTT disconnect, dashboard status, log alertsCross-Module Dependencies
| Module Relationship | Focus |
|---|---|
NetworkManager ↔ WiFiManager | WiFi mode, STA/AP state, reconnect strategy |
NetworkManager → ProtocolManager | MQTT/Modbus init and recovery after network ready |
ProtocolManager → Web/API | MQTT/Modbus status, config save, error codes |
HealthMonitor → Network/Web/SSE | Low-memory degradation, connection cleanup, log throttling |
WebConfigManager → All Modules | REST API routes, authentication, config read/write |
Multi-Chip Compatibility
| Chip | Constraints |
|---|---|
| ESP32 | 4MB tight space, serial defaults to UART0 |
| ESP32-S3 | PSRAM can relieve large object allocation, but RMT/IR drivers need separate verification |
| ESP32-C3 | RAM tightest, Lite preset priority |
| ESP32-C6 | Library support differs, OneWire/DallasTemperature etc. need checking |
Any changes involving memory allocation, task stacks, library dependencies, serial, RMT, USB-CDC, PSRAM or lib_ignore must be compiled for the corresponding chip environment.
In-Change Coding Constraints
Defensive Coding
- State checks must cover intermediate states: connecting, disconnecting, failed, low-memory.
- External inputs, JSON fields, config arrays and pin lists must all be boundary-validated.
- High-frequency paths should avoid temporary
Stringconcatenation, large object JSON and frequentnew/delete.
if (currentStatus != WL_DISCONNECTED) {
WiFi.disconnect(false);
delay(100);
}Resource Cleanup
- Confirm whether
WiFi.disconnect()and reconnect task stop are needed before/after WiFi mode switches. new,malloc, file handles, tasks, timers and callback registrations must have release or deregistration paths.- Prefer RAII, static pools, pre-allocated buffers and clear failure returns.
Log Levels
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");- Use throttled logs for high-frequency paths.
- Use INFO for one-time events.
- Use ERROR/WARN for errors and exceptions, with sufficient context.
- Production builds default to
FASTBEE_STRIP_INFO_LOGS=1,FASTBEE_DEBUG_LOG=0.
Type & Interface Safety
- When calling across abstraction layers, verify if the interface belongs to the base class; use explicit casts and null checks when necessary.
- When API response fields are added, removed or change semantics, sync Web UI, test matrix and documentation.
- When config structures gain new fields, sync default config, migration logic, import/export and factory reset.
Frontend Styles
- Prefer reusing
.fb-*component classes and design tokens fromweb-src/css/main.css. - In-page styles should only be used for local overrides genuinely needed by the current page.
- After frontend changes, verify gzip artifact size and static asset integrity.
Post-Change Verification Matrix
The unified entry point is scripts/test-all.ps1. Select checks based on change risk; do not run only a single environment when shared modules, config, network, protocol or Web/API are affected.
| Check | Command | Coverage |
|---|---|---|
| Static Checks | scripts/test-all.ps1 -Checks static | UTF-8, test registration, API matrix, default config, Web static assets, etc. |
| Native Unit Tests | scripts/test-all.ps1 -Checks native | Host-side C++ unit tests |
| Multi-Chip Build | scripts/test-all.ps1 -Checks build | ESP32, C3, C6, S3 release environments |
| Release Artifacts | scripts/test-all.ps1 -Checks artifacts | Merged firmware, LittleFS, manifest |
| Device Smoke | scripts/test-all.ps1 -Checks device-smoke -BaseUrl http://<device IP> -DeviceProfile <lite|standard|full> | Login, system, network, protocol, peripheral, execution, edition capabilities |
| Device Soak | scripts/test-all.ps1 -Checks device-soak -BaseUrl http://<device IP> -DeviceProfile full -SoakRounds 100 | API loops, memory trends, auth stability and response time |
Common local commands:
# Quick pre-commit check
powershell -ExecutionPolicy Bypass -Command ".\scripts\test-all.ps1 -Checks static,build"
# Full local matrix, no real device access
powershell -ExecutionPolicy Bypass -Command ".\scripts\test-all.ps1 -Checks static,native,build,artifacts"
# Single native test
pio test -e native -f test_web_apiHigh-Risk Change Checklist
| Type | Risk | Must Check |
|---|---|---|
| WiFi Mode Switch | Stack overflow, state oscillation, provisioning entry loss | Prohibit unconstrained AP+STA oscillation; clean state before mode switch |
| MQTT Connection Management | Pointless retries on disconnect, memory consumption, main loop blocking | isNetworkConnected() gating, backoff reconnect, low-memory pause |
| Memory Allocation | Heap fragmentation, max contiguous block insufficient, task stack overflow | Prefer PSRAM for large objects, low-memory degradation, avoid high-frequency allocation |
platformio.ini Dependencies | Unused libraries compiled, Flash bloat, chip incompatibility | Check lib_deps, lib_ignore, macros and multi-chip build |
| Web/API Fields | Frontend display anomalies, test matrix mismatch, old config incompatibility | Sync UI, default config, import/export, API tests |
| OTA/File System | Power loss corruption, partition mismatch, recovery failure | Power-loss recovery, checksum failure path, old firmware rollback |
Regression Test Standards
Every bug fix should include a corresponding test. Test files are organized by module and registered in test/run_tests.cpp or the current test entry.
| Bug Type | Test Recommendation |
|---|---|
| Logic Error | Behavioral unit test or source regression test |
| State Machine Error | State transition simulation test |
| Memory Issues | Heap threshold, low-memory protection or long-term stability test |
| Config Errors | Default config, import/export, invalid field tests |
| Multi-Module Collaboration | E2E scenario tests |
| Performance Degradation | Performance benchmark or soak metrics |
When adding device APIs, you must sync scripts/device-api-test-matrix.json and run at least one smoke test for the corresponding tier.
Git Commit Requirements
- One commit per issue, fix and corresponding test in the same commit.
- Use Conventional Commits for commit messages, e.g.,
fix(network): fall back to pure AP mode after STA failure. - Commit body should describe root cause, changes, verification commands and impact scope.
- Do not mix unrelated formatting, doc syncs and feature fixes in one commit.
AI-Assisted Development Notes
- When making requests, prefer providing symptoms, logs, expected behavior and reproduction steps.
- When reviewing changes, check if call sites, state machines, log formats, tests and documentation are in sync.
- AI cannot replace hardware verification; WiFi, MQTT, memory trends, multi-device concurrency and specific sensor compatibility still require real device confirmation.
