Skip to content

Development ​

This document is for developers who want to extend FastBee-Arduino functionality, covering development environment setup, coding standards, testing workflow, extension development and contribution guidelines.

When developing and debugging, first confirm firmware online status and resource margins on the dashboard, then use Logs, Peripherals, and Peripheral Execution to verify behavior. Configuration backup is under Device Configuration > Advanced Configuration.

Device Monitoring Dashboard

Device Log Page

NameStatusTriggerTarget PeripheralActionStatsActions
ADC Voltage Read & ReportDisabledTimer TriggerADC Analog ConversionSensor Data Read -> ADC Analog ConversionTrigger Count: 1Run Once / Edit / Enable / Delete
ADC Voltage Below 2.30V Close RelayDisabledEvent Trigger-Set Low LevelTrigger Count: 1Run Once / Edit / Enable / Delete
ADC Voltage Above 2.50V Open RelayDisabledEvent Trigger-Set High LevelTrigger Count: 1Run Once / Edit / Enable / Delete
ADC Voltage Display on Digital TubeDisabledTimer Trigger-Display NumberTrigger Count: 1Run Once / Edit / Enable / Delete
NTP Time SyncDisabledPlatform Trigger (MQTT)-NTP SyncTrigger Count: 1Run Once / Edit / Enable / Delete
OLED Temp & Humidity DisplayDisabledTimer Trigger-OLED Custom DisplayTrigger Count: 1Run Once / Edit / Enable / Delete
OLED Custom Display - Button Trigger Device InfoDisabledEvent Trigger-OLED Custom DisplayTrigger Count: 1Run Once / Edit / Enable / Delete
OLED Custom Display - Timer MixedDisabledTimer Trigger-OLED Custom DisplayTrigger Count: 1Run Once / Edit / Enable / Delete
OLED Custom Display - MQTT MessageDisabledPlatform Trigger (MQTT)-OLED Custom DisplayTrigger Count: 1Run Once / Edit / Enable / Delete
OTA UpgradeDisabledPlatform Trigger (MQTT)-OTA UpgradeTrigger Count: 1Run Once / Edit / Enable / Delete

After extension development, check whether source code, configuration, Web assets, build environment and device verification records are in sync according to the artifact map, to avoid only updating firmware while missing LittleFS or release notes.

Developers should first study architecture and core framework before diving into specific peripheral, protocol or peripheral execution modules; after changes, return to testing and release path for verification closure.

Development Environment Setup ​

Required Tools ​

ToolVersionPurpose
VSCodeLatestRecommended IDE
PlatformIO IDELatestEmbedded development plugin
ESP32 DevKitESP32/C3/S3Hardware debugging
USB Data CableData transfer capableFlashing and serial debugging

Optional Tools ​

ToolPurpose
PlatformIO Core (CLI)Command-line builds
Node.js 16+Web asset building
GitVersion control
Serial Debug ToolPuTTY/MobaXterm
MQTT ClientMQTT Explorer/MQTTX

Clone Project ​

bash
git clone https://gitee.com/beecue/fastbee-arduino.git
cd FastBee-Arduino

VSCode Configuration ​

  1. Install PlatformIO IDE plugin
  2. Open project folder
  3. PlatformIO auto-downloads dependencies (first time takes a few minutes)
  4. Confirm .vscode/c_cpp_properties.json is generated

Project Structure ​

For directory details, see Project Directory & Files. Brief structure:

FastBee-Arduino/
├── src/          # C++ source (core/network/peripherals/protocols/security/systems/utils)
├── include/      # Header files (mirrors src structure)
├── web-src/      # Web frontend source
├── data/         # Default config and post-build Web assets
├── scripts/      # Build, deploy and test scripts
├── test/         # Native unit tests
├── docs/         # Project documentation
└── platformio.ini # PlatformIO build configuration

Coding Standards ​

C++ Code Standards ​

Naming Conventions:

TypeConventionExample
Class namePascalCasePeripheralManager
Method namecamelCaseinitHardware()
Member variablem_ + camelCasem_peripherals
ConstantUPPER_SNAKE_CASEMAX_PERIPHERALS
Enum valueUPPER_SNAKE_CASEACTION_HIGH
Local variablecamelCasesensorValue
Namespacelowercasefastbee::core

Code Format:

  • Follow .clang-format configuration
  • Indentation: 4 spaces
  • Braces: K&R style (opening brace on same line)
  • Line width: 120 characters

Example:

cpp
class PeripheralManager {
public:
    bool addPeripheral(const PeripheralConfig& config);
    void initHardware();

private:
    std::map<std::string, Peripheral*> m_peripherals;
    bool m_initialized = false;
    static const int MAX_PERIPHERALS = 32;
};

Comment Standards:

  • File header: Brief description of file purpose
  • Class/method: Doxygen style
  • Complex logic: Inline comments explaining why
  • Public API: Complete parameter/return value descriptions
cpp
/**
 * @brief Initialize peripheral hardware
 *
 * Allocate pins based on configuration, initialize drivers and register to peripheral list.
 *
 * @param config Peripheral configuration
 * @return true Initialization successful
 * @return false Initialization failed (pin conflict/driver anomaly)
 */
bool initHardware(const PeripheralConfig& config);

Frontend Code Standards ​

Naming Conventions:

  • Variables/functions: camelCase
  • Constants: UPPER_SNAKE_CASE
  • Class names: PascalCase (if applicable)

Code Format:

  • Follow .eslintrc.json configuration
  • Indentation: 4 spaces
  • Strings: Single quotes
  • Semicolons: Required
  • Line width: 120 characters

Example:

javascript
function loadPeripherals() {
    const apiUrl = '/api/peripherals';
    fetch(apiUrl)
        .then(response => response.json())
        .then(data => {
            renderPeripherals(data);
        })
        .catch(error => {
            console.error('Failed to load peripherals:', error);
        });
}

Build Workflow ​

For detailed build, flash and deploy commands, see Deploy, Flash & Test.

powershell
# Build firmware (select corresponding environment)
pio run -e esp32-F4R0
pio run -e esp32c3-F4R0
pio run -e esp32s3-F16R8

# One-step build and flash
powershell -ExecutionPolicy Bypass -File scripts\deploy.ps1 -Env esp32-F4R0 -Port COM6

# Build Web assets only
node scripts/gzip-www.js --env esp32-F4R0

Testing Workflow ​

For detailed test layering, matrix and cases, see Testing & Edition Verification Guide.

powershell
# Quick pre-commit check
powershell -ExecutionPolicy Bypass -Command ".\scripts\test-all.ps1 -Checks static,build"

# Full local matrix
powershell -ExecutionPolicy Bypass -Command ".\scripts\test-all.ps1 -Checks static,native,build,artifacts"

# Run single native test
pio test -e native -f test_web_api

Extension Development ​

Adding a New Peripheral ​

Step 1: Define Peripheral Type ​

Add type enum in include/core/PeripheralTypes.h:

cpp
enum PeripheralType {
    // ... existing types
    YOUR_SENSOR_TYPE = 50,  // Choose unused value
};

Step 2: Implement Driver Class ​

Create driver file in src/peripherals/:

YourSensorDriver.h:

cpp
#pragma once
#include "PeripheralTypes.h"

class YourSensorDriver {
public:
    bool begin(int pin, const std::map<std::string, String>& params);
    float readValue();
    void end();

private:
    int m_pin;
    bool m_initialized = false;
};

YourSensorDriver.cpp:

cpp
#include "YourSensorDriver.h"
#include <Arduino.h>

bool YourSensorDriver::begin(int pin, const std::map<std::string, String>& params) {
    m_pin = pin;
    pinMode(m_pin, INPUT);
    m_initialized = true;
    return true;
}

float YourSensorDriver::readValue() {
    if (!m_initialized) return -1;
    return analogRead(m_pin);
}

void YourSensorDriver::end() {
    m_initialized = false;
}

Step 3: Register to PeripheralManager ​

Add initialization logic in PeripheralManager::initHardware():

cpp
case YOUR_SENSOR_TYPE: {
    auto* driver = new YourSensorDriver();
    if (!driver->begin(pins[0], config.params)) {
        delete driver;
        return false;
    }
    peripheral->setDriver(driver);
    break;
}

Step 4: Add Sensor Read Support ​

Add parsing logic in PeriphExecExecutor::executeSensorRead():

cpp
if (sensorCategory == "your_sensor") {
    auto* driver = static_cast<YourSensorDriver*>(peripheral->getDriver());
    float value = driver->readValue();
    cache[key] = String(value);
    return true;
}

Step 5: Write Documentation ​

  • Create config doc in docs/peripherals/: your-sensor.md
  • Create usage example in docs/examples/: 49-your-sensor.md
  • Update docs/peripherals/sensor-guide-complete.md

Step 6: Test & Verify ​

  • Connect hardware, flash firmware
  • Add peripheral via Web interface
  • Verify sensor readings are normal
  • Create rules to test linked actions

Adding a New Protocol ​

Step 1: Implement Protocol Handler ​

Inherit ProtocolHandler interface:

cpp
class YourProtocolHandler : public ProtocolHandler {
public:
    bool connect(const ProtocolConfig& config) override;
    bool disconnect() override;
    bool publish(const String& topic, const String& payload) override;
    bool subscribe(const String& topic) override;
    bool isConnected() override;

private:
    bool m_connected = false;
};

Step 2: Register to ProtocolManager ​

Add in ProtocolManager::initProtocol():

cpp
if (config.protocolType == "your_protocol") {
    auto* handler = new YourProtocolHandler();
    handler->connect(config);
    m_protocols[config.id] = handler;
}

Step 3: Add API Routes ​

Create route handler in network/handlers/:

YourProtocolRouteHandler.cpp:

cpp
void handleGetConfig(AsyncWebServerRequest* request) {
    // Return protocol configuration
}

void handlePostConfig(AsyncWebServerRequest* request) {
    // Save protocol configuration
}

Register in WebConfigManager::setupRoutes():

cpp
server.on("/api/your-protocol", HTTP_GET, handleGetConfig);
server.on("/api/your-protocol", HTTP_POST, handlePostConfig);

Step 4: Frontend Pages ​

  • Add config page in web-src/pages/: your-protocol.html
  • Add API call logic in web-src/js/
  • Update web-src/modules/ module routing

Step 5: Write Documentation ​

  • Create protocol doc in docs/protocols/
  • Update docs/protocols/README.md

Contribution Guidelines ​

PR Submission Workflow ​

  1. Fork Project

    • Fork the repository on Gitee/GitHub
  2. Create Feature Branch

    bash
    git checkout -b feature/your-feature-name
  3. Commit Changes

    bash
    git add .
    git commit -m "feat: add your feature description"
  4. Push to Branch

    bash
    git push origin feature/your-feature-name
  5. Open Pull Request

    • Create PR in the repository
    • Describe feature, test status and related issues in detail

Commit Standards ​

Follow Conventional Commits:

TypeDescriptionExample
featNew featurefeat: add BMP280 sensor driver
fixBug fixfix: resolve MQTT reconnect issue
docsDocumentation updatedocs: add architecture diagram
styleCode formattingstyle: fix indentation
refactorRefactoringrefactor: simplify peripheral init
testTest relatedtest: add peripheral unit tests
choreBuild/toolingchore: update platformio.ini

Code Review Checklist ​

Functionality Completeness:

  • Features implemented as required
  • Edge cases handled
  • Error handling is comprehensive

Memory Safety:

  • No memory leaks (new/delete paired)
  • No buffer overflows
  • Null checks before pointer use

Build Quality:

  • No compiler warnings
  • Passes all unit tests
  • Follows coding standards

Documentation Sync:

  • Related documentation updated
  • Code comments added
  • CHANGELOG updated (if applicable)

Performance Considerations:

  • Avoid frequent memory allocation
  • Use reference passing for large objects
  • Async processing for time-consuming operations

Debugging Tips ​

Serial Logging ​

Output Logs:

cpp
Serial.printf("[YOUR_MODULE] Message: %s\n", value.c_str());
Serial.printf("[YOUR_MODULE] Value: %d, Float: %.2f\n", intVal, floatVal);

Log Levels:

cpp
ESP_LOGE("TAG", "Error message");   // Error
ESP_LOGW("TAG", "Warning message"); // Warning
ESP_LOGI("TAG", "Info message");    // Info
ESP_LOGD("TAG", "Debug message");   // Debug

Memory Diagnostics ​

View Memory Status:

cpp
Serial.printf("Free heap: %lu bytes\n", ESP.getFreeHeap());
Serial.printf("Max alloc: %lu bytes\n", ESP.getMaxAllocHeap());
Serial.printf("Min free heap: %lu bytes\n", ESP.getMinFreeHeap());

PSRAM Status:

cpp
#ifdef BOARD_HAS_PSRAM
    Serial.printf("PSRAM size: %lu bytes\n", ESP.getPsramSize());
    Serial.printf("Free PSRAM: %lu bytes\n", ESP.getFreePsram());
#endif

Web API Debugging ​

Browser Developer Tools:

  1. Open Network panel
  2. View API request/response
  3. Check JSON format
  4. View response status codes

curl Testing:

bash
# Get peripheral list
curl http://192.168.4.1/api/peripherals

# Add a peripheral
curl -X POST http://192.168.4.1/api/peripherals \
  -H "Content-Type: application/json" \
  -d '{"id":"test_01","name":"Test","type":12,"enabled":false,"pinCount":1,"pins":[26,255,255,255,255,255,255,255],"params":{}}'

Common Issue Troubleshooting ​

IssueTroubleshooting Steps
Web not accessibleCheck WiFi connection, IP address, firewall
Peripheral not respondingCheck pin config, enable status, wiring
MQTT disconnectedCheck server address, port, credentials
Insufficient memoryDisable unnecessary runtime features, reduce concurrency, then choose a higher-resource environment if needed
Build failedClean build, check dependencies, update PlatformIO
Upload failedCheck USB connection, driver, serial port usage

Performance Profiling ​

CPU Usage:

cpp
uint32_t start = micros();
your_function();
uint32_t elapsed = micros() - start;
Serial.printf("Execution time: %lu us\n", elapsed);

Stack Usage:

cpp
#include <esp_task.h>
Serial.printf("Stack high water: %lu bytes\n", uxTaskGetStackHighWaterMark(NULL));

FastBee | fastbee.cn