How to Flash a Custom Binary with esp_flasher CLI: Complete Command-Line Guide
Run esp_flasher path/to/your_firmware.bin to auto-detect your ESP device and flash a custom binary, or use flags like -p /dev/ttyUSB0 and --esp32 for explicit control over the programming process.
The esp_flasher tool from the jason2866/esp_flasher repository provides a streamlined Python wrapper around esptool for programming ESP8266 and ESP32 microcontrollers. Using the esp_flasher CLI, you can deploy custom firmware with automatic chip detection, configurable partition tables, and variable baud rates. The command-line interface is implemented in esp_flasher/__main__.py and orchestrates the complete workflow from serial port selection to post-flash monitoring.
Installation and Prerequisites
Install the package via pip to access the esp_flasher command:
pip install esp-flasher
Alternatively, download pre-built binaries from the repository's Releases page. You need Python 3.7+ and a USB-to-serial driver appropriate for your ESP development board.
Basic CLI Usage
Flash with Auto-Detection
The simplest invocation flashes your binary while automatically detecting the serial port and chip family:
esp_flasher firmware.bin
According to the source code in esp_flasher/__main__.py, the tool calls get_port_list() from own_esptool.py to enumerate available ports if you omit the -p flag. It then uses detect_chip() from common.py to identify whether the target is an ESP8266, ESP32, ESP32-S2, or other variant.
Specify Serial Port and Chip Family
For explicit control, provide the port path and chip flag:
esp_flasher -p /dev/ttyUSB0 --esp32 firmware.bin
Available chip flags include --esp8266, --esp32, --esp32s2, --esp32s3, and --esp32c3. These bypass auto-detection and force the loader to use chip-specific parameters defined in the configure_write_flash_args function.
Advanced Configuration Options
Custom Bootloader and Partition Tables
You can override the default bootloader, partition table, and OTA data by specifying URLs or local file paths:
esp_flasher \
--bootloader https://example.com/bootloader.bin \
--partitions partitions.bin \
--otadata ota_data.bin \
--esp32 firmware.bin
Default URLs for these components are stored in esp_flasher/const.py. The wrapper downloads remote resources on-the-fly before constructing the WriteFlashArgs object that configures the flashing parameters.
Optimize Upload Speed
Increase the baud rate to reduce transfer time for large binaries:
esp_flasher --upload-baud-rate 921600 --esp32 firmware.bin
As implemented in esp_flasher/__main__.py, if the chip fails to synchronize at the requested speed, the tool automatically falls back to 115200 bps. The baud change occurs before flash size probing to maximize throughput during the esptool.write_flash operation.
Skip Flash Erasure
To preserve existing flash contents and write only your binary, use the --no-erase flag:
esp_flasher --no-erase firmware.bin
By default, esp_flasher calls esptool.erase_flash before writing. Disabling this step is useful for incremental updates or when you want to retain calibration data stored in other flash regions.
Post-Flash Monitoring
View serial logs immediately after flashing without reprogramming:
esp_flasher --show-logs -p /dev/ttyUSB0
This opens the port at 115200 bps, prints timestamps, and streams UART output until you terminate the process. The logging functionality reuses the same serial detection logic found in the main flashing workflow.
Complete Workflow Example
The following example flashes a Tasmota binary to an ESP32-S3 with a custom partition table:
# Install the tool
pip install esp-flasher
# Flash with custom configuration
esp_flasher \
-p /dev/ttyUSB1 \
--esp32s3 \
--partitions custom_partitions.bin \
--upload-baud-rate 921600 \
tasmota.bin
Expected output includes chip identification details from detect_chip(), confirmation of the flash size, and a hard reset message before log streaming begins.
Understanding the Source Code Flow
The run_esp_flasher(argv) function in esp_flasher/__main__.py serves as the entry point that processes sys.argv. The execution flow follows these distinct phases:
- Argument Parsing: Validates the binary path and optional flags for chip family, port, and baud rate.
- Port Selection: Uses
get_port_list()if no port is specified. - Chip Detection: Invokes
detect_chip()to determine the exact ESP variant and flash characteristics. - Parameter Configuration: Builds a
WriteFlashArgsinstance with offsets for bootloader, partitions, and application binary. - Flash Operations: Optionally erases flash, writes the binary via
esptool.write_flash, and performs a hard reset. - Log Streaming: Continuously reads UART output at 115200 bps if monitoring is enabled.
This architecture allows esp_flasher to abstract esptool's complexity while exposing essential configuration hooks through the CLI.
Summary
- Install
esp_flashervia pip to access the CLI wrapper around esptool. - Flash binaries with auto-detection using
esp_flasher firmware.bin, or specify ports and chip families with-pand--esp32flags. - Customize configurations by providing
--bootloader,--partitions, and--otadataarguments that accept local files or HTTP URLs. - Optimize transfers with
--upload-baud-rateup to 921600, with automatic fallback to 115200 if synchronization fails. - Monitor output using
--show-logsto stream UART data without re-flashing.
Frequently Asked Questions
What is the difference between esp_flasher and esptool?
esp_flasher is a Python wrapper that simplifies esptool by providing opinionated defaults, automatic chip detection via detect_chip() in common.py, and integrated post-flash logging. While esptool requires manual specification of flash addresses and chip types, esp_flasher automates these steps using the logic in esp_flasher/__main__.py and configuration constants from esp_flasher/const.py.
Can I flash multiple binaries at once?
Yes, but indirectly. The CLI accepts a single application binary as the positional argument, but you can simultaneously flash a bootloader, partition table, and OTA data using the respective flags. These components are combined into a single WriteFlashArgs structure that esptool.write_flash processes as one atomic operation.
How do I fix "Failed to connect to ESP" errors?
Ensure your device is in bootloader mode by holding the BOOT button while resetting, or check that the specified -p port is correct. The get_port_list() function in own_esptool.py only detects ports where the ESP is responsive; if auto-detection fails, manually specify the port and verify your USB cable supports data transfer (not power-only).
Does esp_flasher support ESP32-C6 or ESP32-H2?
Support depends on the bundled esptool version and the chip detection logic in common.py. The repository regularly updates to support newer ESP variants. Use the appropriate chip flag (e.g., --esp32c3, --esp32s3) or omit it entirely to let detect_chip() identify the silicon revision automatically.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →