Skip to content

perf(deploy): replace esptool subprocess with espflash native crate #66

Closed

Description

@zackees

Split out from #18 item 5.

Problem

verify-flash and write-flash currently shell out to Python esptool. Cost breakdown for verifying a 2.4 MB ESP32-S3 image (~5.9 s total):

Phase Estimated cost
Python interpreter startup ~1 s
Subprocess spawn + esptool init ~0.5 s
Connect + reset chip into bootloader ~1 s
SYNC handshake + stub flasher upload ~1 s
Baud rate change ~0.5 s
FLASH_MD5SUM execution (3 regions, 2.4 MB) ~1 s
Cleanup + reset back to app ~0.5 s

Actual MD5 work is ~1 s; the rest is process/Python overhead.

Proposed fix

Use the espflash crate — Rust-native ESP32 flasher protocol maintained by ESP-RS. Exposes SLIP protocol, stub flasher loading, and FLASH_MD5SUM natively.

espflash = { version = "4", default-features = false, features = ["serialport"] }

Reuse the daemon's existing serial port lease instead of spawning a subprocess.

Estimated win

  • First verify in a session: ~5.9 s → ~1.5–2 s
  • Subsequent verifies reusing the loaded stub flasher: <1 s

Effort

Medium. The espflash library API is less stable than the CLI — may need an adapter layer between fbuild's Esp32Deployer and espflash's Flasher type. Worth a spike to confirm feasibility before committing.

Context

Filed during the issue consolidation that closed tracker #18. See #18 for the original framing.

Activity

  1. zackees commented on Apr 18, 2026

    @zackees
    MemberAuthor

    Progress update — verify-flash migrated:

    Remaining: write-flash migration. Deferred from PR #89 for two reasons: (1) needs a progress-callback bridge to the daemon's WebSocket log stream so users see upload progress, (2) stricter error recovery for partial writes / USB re-enumeration. Picking that up next.

  2. zackees commented on Apr 18, 2026

    @zackees
    MemberAuthor

    Shipped the /ws/logs bridge in #111 (merged as e7aad0e). BroadcastLogLayer forwards tracing events to the existing BroadcastHub::log_tx channel, so the 10%-throttled native write-flash progress lines emitted by esp32_native::LoggingProgressBridge now stream live on /ws/logs. Zero-subscriber overhead is one atomic load; self-echo cycles are guarded by a module-path filter on handlers::websockets. Closes the "progress-callback bridge to the daemon WebSocket log stream" follow-up from the comment above — leaving only the stricter partial-write / USB re-enumeration error-recovery item on this issue.

  3. zackees commented on Apr 22, 2026

    @zackees
    MemberAuthor

    Current status (2026-04-22): closing this as code-complete.

    What landed:

    Current main has crates/fbuild-deploy/src/esp32_native.rs implementing both native verify and write. The write path short-circuits on region failure, reports the failed region/offset/byte progress, returns a failed DeploymentResult instead of silently swallowing partial writes, and the daemon clears the trusted firmware hash on failed/partial deploys. The daemon also still runs the post-deploy USB re-enumeration poll for every non-VerifySkip result.

    Important operational note: the native path is still deliberately opt-in. The daemon must be built with espflash-native, then enabled at runtime with FBUILD_USE_ESPFLASH_VERIFY=1 and/or FBUILD_USE_ESPFLASH_WRITE=1. The default remains the esptool subprocess path until hardware validation/default-flip policy is handled separately.

    Local verification on main (61b18fe8):

    cargo test -p fbuild-deploy --features espflash-native esp32_native
    21 passed; 0 failed
    

    Closing #66 because the original esptool-to-espflash migration is implemented. Any remaining "make this the default after hardware benching across ESP32 families" work should be tracked as a separate validation/default-flip issue rather than keeping this implementation issue open.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions