Skip to content

feat: add OTA firmware update for ESP32 platforms#54

Merged
zevorn merged 6 commits intomainfrom
feat/ota-esp32
Mar 17, 2026
Merged

feat: add OTA firmware update for ESP32 platforms#54
zevorn merged 6 commits intomainfrom
feat/ota-esp32

Conversation

@zevorn
Copy link
Copy Markdown
Owner

@zevorn zevorn commented Mar 17, 2026

Summary

  • Add HTTP GET to OSAL network layer (claw_net_get()) for lightweight requests
  • Add OTA firmware update service using board-interface pattern (not OSAL abstraction)
  • ESP-IDF implementation via esp_ota_ops A/B partition switching
  • AI tools (ota_check, ota_update, ota_version, ota_rollback) for AI-driven OTA
  • Shell command /ota check|update|rollback|version for interactive use
  • 15 unit tests covering version compare, JSON parse, and tool registration

Architecture

OTA follows the board interface pattern (like claw_board.h):

include/claw_ota.h              ← platform callback interface
claw/services/ota/ota_service.c ← business logic (version check, worker thread)
platform/common/espressif/esp_ota.c ← ESP-IDF implementation
claw/tools/tool_ota.c           ← AI tool use integration

Target Boards

Board Flash OTA Partition Status
xiaozhi-xmini (C3) 16MB ota_0 + ota_1 (2MB each) Ready
ESP32-S3 default 16MB ota_0 + ota_1 (2MB each) Ready
ESP32-C3 devkit 4MB N/A Not supported
QEMU (all) N/A factory only Not supported

Test plan

  • Meson build passes with -Dota=true (vexpress-a9 cross)
  • scripts/check-patch.sh passes on all new/modified files
  • make test-unit passes (15 OTA tests + existing suites)
  • make build-esp32c3-xiaozhi-xmini compiles with OTA enabled
  • Boot test on QEMU (OTA service init gracefully fails without OTA partition)

Closes #53

zevorn added 6 commits March 17, 2026 18:23
Extend the network abstraction layer with HTTP GET for lightweight
requests (e.g. OTA version check JSON).  Both ESP-IDF and RT-Thread
backends implement the new function following the same pattern as
the existing claw_net_post().

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
Add Over-The-Air update support following the board-interface pattern
(claw_ota.h), not OSAL abstraction — OTA is fundamentally a platform
operation (flash write, partition switch, bootloader interaction).

New components:
- claw_ota.h: platform OTA callback interface
- ota_service.c: version check, JSON parse, update worker thread
- esp_ota.c: ESP-IDF implementation (esp_ota_ops A/B partition)
- tool_ota.c: AI tools (ota_check, ota_update, ota_version, ota_rollback)
- /ota shell command (check|update|rollback|version)

Build integration:
- Meson: -Dota=true feature flag, OTA URL/interval config overrides
- Kconfig: CONFIG_RTCLAW_OTA_ENABLE for ESP32-C3 and S3
- CMake: app_update component dependency
- sdkconfig: rollback enabled on xiaozhi-xmini and S3 default

Target boards: xiaozhi-xmini (C3, 16MB) and ESP32-S3 default (16MB),
both already have OTA dual-partition tables (ota_0 + ota_1 + otadata).

Closes #53

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
15 test cases covering OTA pure-logic functions:
- version_compare: equal, major/minor/patch, mixed precedence
- parse_version_json: full/minimal/spaced JSON, missing fields,
  empty input, field truncation
- trigger_update: NULL and empty URL rejection
- tool registration: all 4 OTA AI tools present

Platform OTA functions are stubbed (no real flash needed).
Test runner enables -Dota=true automatically via run.py.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
On ESP-IDF the CONFIG_RTCLAW_OTA_ENABLE flag comes from Kconfig
(sdkconfig → cross.ini), not from Meson -Dota=true.  When sdkconfig
enables OTA but Meson ota=false (the default), OTA call-sites in
claw_init.c and shell_commands.c are active but OTA source files
are missing, causing undefined reference errors at link time.

Fix: always include ota_service.c, tool_ota.c, and test_ota.c in
the build.  The #ifdef CONFIG_RTCLAW_OTA_ENABLE inside each file
controls whether any code is emitted.  This matches the pattern
used by swarm, sched, ai_engine, and other modules.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
esp_ota.c was compiled into libmain.a, but the Meson-compiled
ota_service.o (in librt_claw.a) references its symbols.  ESP-IDF
links librt_claw.a before libmain.a, so the linker cannot resolve
claw_ota_platform_init, claw_ota_running_version, etc.

Fix: compile esp_ota.c as part of the rt_claw component so all OTA
symbols live in the same static library.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
During firmware flashing/erasing, output now goes directly to the
right-side Serial Monitor panel instead of a separate flash-log div.
All serial controls (Connect, Reset, Clear, baudrate, input, Send)
are disabled during flash to prevent conflicts, except the Expand
button which remains usable.

Signed-off-by: Chao Liu <chao.liu.zevorn@gmail.com>
@zevorn zevorn merged commit e90684b into main Mar 17, 2026
8 checks passed
@zevorn zevorn deleted the feat/ota-esp32 branch March 17, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add OTA support for ESP32 platforms

1 participant