### Install esptool with pip Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/index.html Install esptool using pip. This is the first step in the quick start guide. ```bash $ pip install esptool ``` -------------------------------- ### Install and enable pre-commit hooks Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html Commands to install the pre-commit framework and enable the required git hooks for automated code checks. ```bash $ python -m pip install pre-commit $ pre-commit install -t pre-commit -t commit-msg ``` -------------------------------- ### Install development dependencies for esptool Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html Installs esptool plus additional packages useful for development using setuptools extras. This is needed for actually developing and testing esptool. ```bash $ pip install --user -e ".[dev]" ``` -------------------------------- ### pip install esptool==5.1.0 error output Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/troubleshooting.html Shows the error output when installing esptool 5.1.0 with an outdated setuptools version. The error indicates that the package metadata reports an unknown project name, causing pip to reject the installation. To resolve, upgrade setuptools to at least 64.0.0 using `pip install setuptools>=64`. ```text $ pip install esptool==5.1.0 Collecting esptool==5.1.0 .... WARNING: Generating metadata for package esptool produced metadata for project name unknown. Fix your #egg=esptool fragments. Discarding https://files.pythonhosted.org/packages/.../esptool-5.1.0.tar.gz (from https://pypi.org/simple/esptool/) (requires-python:>=3.10): Requested unknown from https://files.pythonhosted.org/packages/.../esptool-5.1.0.tar.gz has inconsistent name: filename has 'esptool', but metadata has 'unknown' ERROR: Could not find a version that satisfies the requirement esptool==5.1.0 (from versions: 4.0, 4.0.1, 4.1, 4.2, 4.2.1, 4.3, 4.4, 4.5, 4.5.1, 4.6, 4.6.1, 4.6.2, 4.7.0, 4.8.0, 4.8.1, 4.9.0, 4.10.0, 4.11.0, 5.0.0, 5.0.1, 5.0.2, 5.1.0) ERROR: No matching distribution found for esptool==5.1.0 ``` -------------------------------- ### ESP32 ROM Boot Mode Message Example Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/boot-mode-selection.html Example output printed by the ESP32 ROM at 115200bps after reset. The second line shows the reset reason (rst:0x1 POWERON_RESET) and boot mode (boot:0x3 DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2)). ```text ets Jun 8 2016 00:22:57 rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2)) ``` -------------------------------- ### Install esptool in a virtual environment Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/installation.html Commands for installing esptool in a virtual environment. Create a venv named 'esptoolenv', activate it (Windows vs Linux/macOS), install esptool, use it, and deactivate when done. The environment can be reused by activating it again. ```bash python -m venv esptoolenv ``` ```bash esptoolenv\Scripts\activate ``` ```bash source esptoolenv/bin/activate ``` ```bash pip install esptool ``` ```bash esptool ``` ```bash deactivate ``` -------------------------------- ### Install esptool with pip Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/installation.html Installs the latest stable esptool release from PyPI. Requires Python 3.10 or newer. If this command fails, try `python -m pip install esptool` or `pip3 install esptool`. ```bash $ pip install esptool ``` -------------------------------- ### Override flash settings with write-flash Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/flash-modes.html Example of using --flash-mode and --flash-size arguments when writing a bootloader image. ```bash esptool --port /dev/ttyUSB1 write-flash --flash-mode dio --flash-size 4MB 0x0 bootloader.bin ``` -------------------------------- ### Clone and install esptool in development mode Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html Clones the esptool repository and installs it in development mode with pip. This creates executable script wrappers that run directly from the working directory, so changes are picked up automatically. ```bash $ git clone https://github.com/espressif/esptool.git $ cd esptool $ pip install --user -e . ``` -------------------------------- ### Using esptool.main() to pass CLI arguments Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Passes the same arguments as the CLI to esptool.main() for basic integration. The example reads flash memory and saves it to a file. ```python import esptool command = ['--baud', '460800', 'read-flash', '0', '0x200000', 'flash_contents.bin'] print("Using command ", " ".join(command)) esptool.main(command) ``` -------------------------------- ### Run all esptool integration tests on real hardware Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html Command format for running test_esptool.py against real Espressif hardware. Requires a serial port, chip name, and baud rate. Example runs all tests on an ESP32 board at /dev/ttyUSB0 with 230400 baud. ```bash pytest test_esptool.py --port --chip --baud ``` ```bash pytest test_esptool.py --port /dev/ttyUSB0 --chip esp32 --baud 230400 ``` -------------------------------- ### Convert ELF to Binary with custom output filename Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html Example of converting an ELF file where the output binary defaults to the same name with a .bin extension. ```bash esptool --chip ESP32 elf2image my_esp_app.elf ``` -------------------------------- ### Sample trace output for initial synchronization sequence Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/serial-protocol.html Example trace output showing part of the initial synchronization sequence with many 0x55 bytes (ASCII 'U'). The split display shows hexadecimal bytes on the left and ASCII on the right, with non-printable characters as '.'. Note the multiple 'Received full packet' lines. ```plaintext TRACE +0.000 Write 46 bytes: c000082400000000 0007071220555555 | ...$........ UUU 5555555555555555 5555555555555555 | UUUUUUUUUUUUUUUU 5555555555555555 5555555555c0 | UUUUUUUUUUUUU. TRACE +0.012 Read 1 bytes: c0 TRACE +0.000 Read 63 bytes: 0108040007071220 00000000c0c00108 | ....... ........ 0400070712200000 0000c0c001080400 | ..... .......... 0707122000000000 c0c0010804000707 | ... ............ 122000000000c0c0 01080400070712 | . ............. TRACE +0.000 Received full packet: 010804000707122000000000 TRACE +0.000 Received full packet: 010804000707122000000000 ``` -------------------------------- ### Run RFC2217 Server and Client Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/remote-serial-ports.html Commands to start the modified RFC2217 server on the host machine and connect to it from the client using the ign_set_control flag to handle network latency. ```bash esp_rfc2217_server -p 4000 /dev/ttyUSB1 ``` ```bash esptool --port rfc2217://ADDRESS_OF_SERVER:4000?ign_set_control flash-id ``` -------------------------------- ### Example of eFuse summary error output Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/check-error-cmd.html This log shows an example of an error detected in BLOCK0 during a summary check. ```text > espefuse summary ... WDT_DELAY_SEL (BLOCK0)[FAIL:1] Selects RTC WDT timeout threshold at startup = False R/W (0b0) ... Error(s) in BLOCK0 [ERRORS:1 FAIL:1] BLOCK0 ( ) [0 ] err__regs: 00000400 00000000 00000000 00000000 00000000 00000000 EFUSE_RD_RS_ERR0_REG 0x00000000 EFUSE_RD_RS_ERR1_REG 0x00000000 WARNING: Coding scheme has encoding bit error warnings ``` -------------------------------- ### Flash encryption key file content Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/burn-key-cmd.html Example content of a 256-bit flash encryption key file. ```text 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f ``` -------------------------------- ### esp_efuse_custom_table.csv example Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html Example of an esp_efuse_custom_table.csv file. It defines single eFuse fields, structured eFuse fields, and non-sequential bit fields. Non-sequential fields are split into sub-fields with _0 and _1 postfixes for safer handling. ```csv MODULE_VERSION, EFUSE_BLK3, 56, 8, Module version DEVICE_ROLE, EFUSE_BLK3, 64, 3, Device role SETTING_1, EFUSE_BLK3, 67, 6, [SETTING_1_ALT_NAME] Setting 1 SETTING_2, EFUSE_BLK3, 73, 5, Setting 2 ID_NUM, EFUSE_BLK3, 140, 8, [MY_ID_NUM] comment , EFUSE_BLK3, 132, 8, [MY_ID_NUM] comment , EFUSE_BLK3, 122, 8, [MY_ID_NUM] comment CUSTOM_SECURE_VERSION, EFUSE_BLK3, 78, 16, Custom secure version ID_NUMK, EFUSE_BLK3, 150, 8, [MY_ID_NUMK] comment , EFUSE_BLK3, 182, 8, [MY_ID_NUMK] comment MY_DATA, EFUSE_BLK3, 190, 10, My data MY_DATA.FIELD1, EFUSE_BLK3, 190, 7, Field1 ``` -------------------------------- ### Burn flash encryption key Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/burn-key-cmd.html Example of burning a flash encryption key, showing the interactive confirmation process and the automatic byte reversal. ```bash > espefuse burn-key flash_encryption 256bit_fe_key.bin === Run "burn-key" command === Sensitive data will be hidden (see --show-sensitive-info) Burn keys to blocks: - BLOCK1 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] Reversing the byte order Disabling read to key block Disabling write to key block Burn keys in efuse blocks. The key block will be read and write protected Check all blocks for burn... idx, BLOCK_NAME, Conclusion [00] BLOCK0 is empty, will burn the new value [01] BLOCK1 is empty, will burn the new value . This is an irreversible operation! Type 'BURN' (all capitals) to continue. BURN BURN BLOCK1 - OK (write block == read block) BURN BLOCK0 - OK (write block == read block) Reading updated efuses... Successful ``` -------------------------------- ### Sample trace output for READ_REG command Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/advanced-topics/serial-protocol.html Example trace output showing a READ_REG command and response. The +X.XXX values are time deltas in seconds, and values are printed in hexadecimal. The 'Write X bytes' and 'Read X bytes' lines show bytes over the wire including SLIP framing, while 'Received full packet' shows the SLIP payload with escaping removed. ```plaintext TRACE +0.000 --- Cmd READ_REG (0x0a) | data_len 4 | wait_response 1 | timeout 3.000 | data 00100040 --- TRACE +0.000 Write 14 bytes: c0000a04000000000000100040c0 TRACE +0.046 Read 1 bytes: c0 TRACE +0.000 Read 11 bytes: 010a0200090000000000c0 TRACE +0.000 Received full packet: 010a0200090000000000 ``` -------------------------------- ### espefuse --extend-efuse-table command Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html Use this command with any supported espefuse command to access custom eFuse fields defined in an ESP-IDF CSV file. The example uses the summary command with an esp32 chip. ```bash > espefuse -c esp32 --extend-efuse-table path/esp_efuse_custom_table.csv summary ``` -------------------------------- ### Dump Memory Region with dump-mem Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/advanced-commands.html Dumps a specified region from the chip's memory space to a file. This example dumps 64 kB of ROM from an ESP8266. ```bash esptool dump-mem 0x40000000 64k iram0.bin ``` -------------------------------- ### Decode token with espefuse --token summary --active Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/token.html Use the --token option to decode a token and print a human-readable eFuse summary. The --active flag limits output to fields that are present/set in the token, reducing noise when sharing logs. The second example shows a full token string for an esp32c3 chip. ```shell espefuse --token summary --active ``` ```shell espefuse --token EFSR:esp32c3:004:AAGAAAEAAAAAAAAEAAAAAAAAAAAAAAAA:AAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAA:AgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA::::::::::epNVBg summary --active ``` -------------------------------- ### espefuse burn-block-data --offset 6 BLOCK3 device_id.bin Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/burn-block-data-cmd.html Burns data from device_id.bin into eFuse BLOCK3 starting at byte offset 6. The output shows the expected confirmation prompt and success message. Requires espefuse v2.6 or newer. ```console > espefuse -p PORT burn-block-data --offset 6 BLOCK3 device_id.bin === Run "burn-block-data" command === [03] BLOCK3 size=32 bytes, offset=06 - > [00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 00 00 00 00 00 00 00 00 00]. Check all blocks for burn... idx, BLOCK_NAME, Conclusion [03] BLOCK3 is empty, will burn the new value . This is an irreversible operation! Type 'BURN' (all capitals) to continue. BURN BURN BLOCK3 - OK (write block == read block) Reading updated efuses... Successful ``` -------------------------------- ### espefuse summary output with User fuses Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/index.html Output of the espefuse summary command when the example CSV file is included. It shows the generated 'User fuses' section with field names, aliases, bit ranges, and current values. The summary includes the used bit range in a comment, such as (150-157) len = 8 bits. ```text User fuses: MODULE_VERSION (BLOCK3) Module version (56-63) = 0 R/W (0x00) DEVICE_ROLE (BLOCK3) Device role (64-66) = 0 R/W (0b000) SETTING_1 (BLOCK3) [SETTING_1_ALT_NAME] Setting 1 (67-72) = 0 R/W (0b000) SETTING_2 (BLOCK3) Setting 2 (73-77) = 0 R/W (0b00000) ID_NUM_0 (BLOCK3) [MY_ID_NUM] comment (140-147) = 0 R/W (0x00) ID_NUM_1 (BLOCK3) [MY_ID_NUM] comment (132-139) = 0 R/W (0x00) ID_NUM_2 (BLOCK3) [MY_ID_NUM] comment (122-129) = 0 R/W (0x00) CUSTOM_SECURE_VERSION (BLOCK3) Custom secure version (78-93) = 0 R/W (0x0000) ID_NUMK_0 (BLOCK3) [MY_ID_NUMK] comment (150-157) = 0 R/W (0x00) ID_NUMK_1 (BLOCK3) [MY_ID_NUMK] comment (182-189) = 0 R/W (0x00) MY_DATA (BLOCK3) My data (190-199) = 0 R/W (0b0000000000) MY_DATA_FIELD1 (BLOCK3) Field1 (190-196) = 0 R/W (0b0000000) ``` -------------------------------- ### run Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Execute the firmware loaded on the ESP device. ```APIDOC ## run ### Description Execute the firmware loaded on the ESP device. ### Parameters - **esp** (ESPLoader) - Required - Initiated esp object connected to a real device. ### Returns None ### Example ```python from esptool.cmds import connect_esp, run with connect_esp() as esp: run(esp) ``` ``` -------------------------------- ### Using Batch Mode for eFuse Operations Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/scripting.html Demonstrates enabling batch mode via init_commands, queuing operations like burning keys and setting eFuses, and executing them with burn_all. Includes verification steps to ensure eFuses were set correctly. ```python from espefuse import init_commands PORT = "/dev/ttyACM0" # Connect to chip and enable batch mode with init_commands(port=PORT, batch_mode=True) as espefuse: # Queue multiple eFuse operations with open("flash_encryption_key.bin", "rb") as f: espefuse.burn_key(["flash_encryption"], [f], no_protect_key=True) espefuse.burn_efuse({"FLASH_CRYPT_CNT": 0x7}) espefuse.burn_efuse({"DISABLE_DL_ENCRYPT": 1}) espefuse.burn_efuse({"JTAG_DISABLE": 1}) # Execute all queued eFuse operations espefuse.burn_all() # Check that all eFuses are set properly espefuse.summary() # Checks written eFuses if espefuse.efuses["FLASH_CRYPT_CNT"].get() != 0x7: raise esptool.FatalError("FLASH_CRYPT_CNT was not set") if espefuse.efuses["DISABLE_DL_ENCRYPT"].get() != 1: raise esptool.FatalError("DISABLE_DL_ENCRYPT was not set") if espefuse.efuses["JTAG_DISABLE"].is_readable() or espefuse.efuses["JTAG_DISABLE"].is_writeable(): raise esptool.FatalError("JTAG_DISABLE should be read and write protected") ``` -------------------------------- ### Run host test suite Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html Runs the whole test suite without tests needing actual hardware or additional prerequisites. Execute from the esptool root folder. ```bash pytest -m host_test ``` -------------------------------- ### Connect, run stub, change baud, and attach flash with esptool.cmds Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Shows the recommended high-level workflow: auto-discover the port, auto-detect the chip, optionally upload the stub flasher, raise the baud rate to 921600, and attach flash. Raises FatalError if no Espressif device can be reached on any candidate serial port. ```python from esptool.cmds import connect_esp, attach_flash, run_stub # Auto-discover the port and auto-detect the chip with connect_esp() as esp: esp = run_stub(esp) # Optional: upload the stub flasher esp.change_baud(921600) # Upgrade to a faster operational rate attach_flash(esp) ... ``` -------------------------------- ### Run esptool SDM integration tests Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html Command format for test_esptool_sdm.py, which tests esptool with chips in secure download mode. Requires real hardware with active SDM. The format is the same as for test_esptool.py. ```bash pytest test_esptool.py --port --chip --baud ``` -------------------------------- ### pySerial error example: read failed: [Errno 6] Device not configured Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/troubleshooting.html Example of a pySerial error message that esptool may print when the serial port cannot be accessed. This error is typically caused by hardware or driver issues, such as the port being in use, the device being disconnected, or missing permissions. ```text A serial exception error occurred: read failed: [Errno 6] Device not configured ``` -------------------------------- ### espefuse.get_esp Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/scripting.html Gets the ESPLoader object for the given chip, using the esptool.cmds.detect_chip() function. ```APIDOC ## espefuse.get_esp ### Description Get the ESPLoader object for the given chip. Uses `esptool.cmds.detect_chip()` function. ### Method Function call ### Endpoint `espefuse.get_esp(port: str | None = None, baud: int = 115200, before: str = 'default-reset', chip: str = 'auto', skip_connect: bool = False, virt: bool = False, debug: bool = False, virt_efuse_file: str | None = None, token: str | None = None) -> ESPLoader | EmulateEfuseControllerBase` ### Parameters - **port** (str | None) - Optional - The port to connect to the chip - **baud** (int) - Optional - The baud rate to connect to the chip - **before** (str) - Optional - The reset mode to use before connecting to the chip. Supported values are: "default-reset", "usb-reset", "no-reset", "no-reset-no-sync" - **chip** (str) - Optional - The chip to use - **skip_connect** (bool) - Optional - Whether to skip connecting to the chip - **virt** (bool) - Optional - Whether to use virtual mode - **debug** (bool) - Optional - Whether to enable debug mode - **virt_efuse_file** (str | None) - Optional - The file to save the eFuse values to - **token** (str | None) - Optional - eFuse token dump (format string: EFSR:esp32:000:…) ### Returns - **ESPLoader | EmulateEfuseControllerBase** - The ESPLoader object or EmulateEfuseController object ``` -------------------------------- ### Initialize Zsh autocompletion Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/installation.html Required initialization steps for Zsh before enabling tool-specific completions. ```bash autoload -U compinit compinit ``` -------------------------------- ### espefuse.main() Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/scripting.html Passes command-line arguments to espefuse, allowing the same operations as the CLI. ```APIDOC ## espefuse.main() ### Description Passes command-line arguments to espefuse, allowing the same operations as the CLI. ### Method main ### Parameters - **command** (list of str) - Required - List of command-line arguments, same as CLI. ### Request Example ```python import espefuse command = ["--port", "/dev/ttyACM0", "summary"] print("Using command ", " ".join(command)) espefuse.main(command) ``` ### Response No return value documented. ``` -------------------------------- ### EfuseFieldBase.get_meaning Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/scripting.html Gets the meaning of the eFuse from a dictionary if possible, suitable for display. Optionally reads from the device or uses cached value. ```APIDOC ## EfuseFieldBase.get_meaning(from_read: bool = True) -> str | int | float | bool ### Description Get the meaning of eFuse from dict if possible, suitable for display. ### Method Function call ### Signature `get_meaning(from_read: bool = True) -> str | int | float | bool` ### Parameters - **from_read** (bool) - Optional - If True, read the eFuse value from the device. If False, use the cached value. ### Returns - **str | int | bool** - The meaning of the eFuse. ``` -------------------------------- ### Update esptool standalone Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/installation.html Use this command to update esptool to the latest version available on PyPI when installed globally or in a virtual environment. ```bash $ pip install --upgrade esptool ``` -------------------------------- ### load_ram Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Load a firmware image into RAM and execute it on the ESP device. ```APIDOC ## load_ram ### Description Load a firmware image into RAM and execute it on the ESP device. ### Parameters - **esp** (ESPLoader) - Required - Initiated esp object connected to a real device. - **input** (str | bytes | IO[bytes]) - Required - Path to the firmware image file, opened file-like object, or the image data as bytes. ### Returns None ### Example ```python from esptool.cmds import connect_esp, load_ram with connect_esp() as esp: load_ram(esp, 'firmware.bin') ``` ``` -------------------------------- ### Display eFuse protection status Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/read-write-protections-cmd.html Example output showing the R/W protection status of a block, where -/W indicates read protection is set. ```text BLOCK1 (BLOCK1): = ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/W ``` -------------------------------- ### Custom ESP32 flash routine using ESPLoader low-level API Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Use this low-level routine to flash a binary to an ESP32 with granular control over the process. It connects via `connect_esp`, reads the firmware file, and writes it in blocks using `flash_begin`, `flash_block`, and `flash_finish`, then resets the chip with `hard_reset`. This is a basic implementation of `esptool -p /dev/ttyACM0 write-flash 0x10000 firmware.bin` and requires a deeper understanding of the ESP chip and esptool internals. ```python from esptool.cmds import connect_esp # The port of the connected ESP PORT = "/dev/ttyACM0" # The binary file BIN_FILE = "./firmware.bin" # Flash offset to flash the binary to FLASH_ADDRESS = 0x10000 def progress_callback(percent): print(f"Wrote: {int(percent)}%") with connect_esp(port=PORT) as esp: description = esp.get_chip_description() features = esp.get_chip_features() print(f"Detected ESP on port {PORT}: {description}") print("Features:", ", ".join(features)) esp = esp.run_stub() with open(BIN_FILE, 'rb') as binary: # Load the binary binary_data = binary.read() total_size = len(binary_data) print(f"Binary size: {total_size} bytes") # Write binary blocks esp.flash_begin(total_size, FLASH_ADDRESS) for i in range(0, total_size, esp.FLASH_WRITE_SIZE): block = binary_data[i:i + esp.FLASH_WRITE_SIZE] # Pad the last block block = block + bytes([0xFF]) * (esp.FLASH_WRITE_SIZE - len(block)) esp.flash_block(block, i + FLASH_ADDRESS) progress_callback(i / total_size * 100) esp.flash_finish() # Reset the chip out of bootloader mode esp.hard_reset() ``` -------------------------------- ### init_commands() Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/scripting.html Context manager that connects to the chip and loads eFuse commands. Provides access to eFuse operations like summary() and efuses. ```APIDOC ## init_commands() ### Description Context manager that connects to the chip and loads eFuse commands. Provides access to eFuse operations like summary() and efuses. ### Method init_commands ### Parameters - **port** (str) - Optional - Serial port to connect to. If not provided, must provide `esp`. - **esp** (ESP object) - Optional - An existing ESP object from esptool. If provided, port is not closed on exit. ### Request Example ```python from espefuse import init_commands PORT = "/dev/ttyACM0" with init_commands(port=PORT) as espefuse: espefuse.summary() # Print the current eFuse values # Get the value of single eFuse custom_mac = espefuse.efuses["CUSTOM_MAC"].get() print(f"CUSTOM_MAC: {custom_mac}") ``` ### Response Returns a context manager that yields an espefuse object with methods: - **summary()** - Prints the current eFuse values. - **efuses** (dict) - Dictionary of eFuse objects, each with a `get()` method to retrieve the value. ``` -------------------------------- ### Read Flash ID via RFC2217 Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/remote-serial-ports.html Example command to read the SPI flash information of a chip connected via an RFC2217 network serial port. ```bash esptool --port rfc2217://192.168.1.77:4000 flash-id ``` -------------------------------- ### connect_first_available Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Iterate `serial_list` and return the first port that connects successfully. `connect_esp()` is the recommended entry point; use this lower-level helper when driving port iteration directly. ```APIDOC ## connect_first_available ### Description Iterate `serial_list` and return the first port that connects successfully. `connect_esp()` is the recommended entry point; use this lower-level helper when driving port iteration directly. ### Parameters - **serial_list** (list[str]) - Required - Candidate serial port devices to try. - **port** (str | None) - Required - Original user-supplied port, or `None` if auto-discovering. When set, the first connection error is re-raised instead of being swallowed to move on to the next candidate. - **connect_attempts** (int) - Required - Number of sync attempts per candidate port. - **initial_baud** (int) - Required - The baud rate used when opening each port for the initial sync (ROM bootloaders typically require 115200). - **chip** (str) - Optional - Target chip name, or `"auto"` to detect. - **trace** (bool) - Optional - Enables or disables tracing for debugging purposes. - **before** (str) - Optional - The chip reset method to perform when connecting (`"default-reset"`, `"usb-reset"`, `"no-reset"`, `"no-reset-no-sync"`). ### Returns A connected ESPLoader instance for the first reachable port, or `None` if no candidate could be connected. ### Example ```python from esptool.cmds import connect_first_available esp = connect_first_available(serial_list=['/dev/ttyUSB0', '/dev/ttyUSB1'], port=None, connect_attempts=7, initial_baud=115200) ``` ``` -------------------------------- ### esptool.cfg sample configuration Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/configuration-file.html Sample esptool configuration file showing how to override default timeout, attempt, and reset sequence settings. The custom_reset_sequence value uses the documented D0|R1|W1.3|D1|R0|W0.5|D0 syntax to add a prolonged delay before reset. ```ini # esptool.cfg file to configure internal settings of esptool [esptool] chip_erase_timeout = 140 serial_write_timeout = 8.5 connect_attempts = 7 write_block_attempts = 2 reset_delay = 0.75 # Overriding the default reset sequence to work in an abnormal environment (prolonged delay): custom_reset_sequence = D0|R1|W1.3|D1|R0|W0.5|D0 ``` -------------------------------- ### Set CLI help theme with RICH_CLICK_THEME Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/advanced-options.html Customize the appearance of the --help output by setting the RICH_CLICK_THEME environment variable. ```bash RICH_CLICK_THEME=solarized-slim esptool -h ``` ```bash export RICH_CLICK_THEME=solarized-slim ``` -------------------------------- ### connect_with_retries Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Repeatedly attempt to open a single, known port and sync with the chip, retrying on failure. `connect_esp()` is the recommended entry point; use this lower-level helper when driving the retry loop directly. ```APIDOC ## connect_with_retries ### Description Repeatedly attempt to open a single, known port and sync with the chip, retrying on failure. `connect_esp()` is the recommended entry point; use this lower-level helper when driving the retry loop directly. ### Parameters - **port** (str) - Required - The serial port to open. - **initial_baud** (int) - Required - The baud rate used when opening the port for the initial sync (ROM bootloaders typically require 115200). - **chip** (str) - Required - Target chip name (e.g. `"esp32"`, `"esp32s3"`). Must be a concrete chip, not `"auto"`. - **max_retries** (int) - Required - Number of attempts before giving up. `0` retries forever until successful. - **trace** (bool) - Optional - Enables or disables tracing for debugging purposes. - **before** (str) - Optional - The chip reset method to perform before each attempt (`"default-reset"`, `"usb-reset"`, `"no-reset"`, `"no-reset-no-sync"`). ### Returns A connected ESPLoader instance for the requested chip. ### Example ```python from esptool.cmds import connect_with_retries esp = connect_with_retries(port='/dev/ttyUSB0', initial_baud=115200, chip='esp32', max_retries=5) ``` ``` -------------------------------- ### Inspect binary image with image-info Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html Displays load addresses, segment sizes, and header information for a .bin file. ```bash esptool image-info my_esp_app.bin ``` -------------------------------- ### run_stub Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Load and execute the stub loader on the ESP device. If stub loading is not supported or is explicitly disabled, warnings are logged. ```APIDOC ## run_stub ### Description Load and execute the stub loader on the ESP device. If stub loading is not supported or is explicitly disabled, warnings are logged. ### Parameters - **esp** (ESPLoader) - Required - Initiated esp object connected to a real device. - **plugins** (list[str] | None) - Optional - Optional list of plugin names to load (e.g. ["nand"]). ### Returns The esp instance, either as a stub child class in a state where the stub has been executed, or in its original state if the stub loader is disabled or unsupported. ### Example ```python from esptool.cmds import connect_esp, run_stub with connect_esp() as esp: esp = run_stub(esp) ``` ``` -------------------------------- ### ESP-IDF build output with esptool flash command Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/flashing-firmware.html ESP-IDF prints this output after a successful build, showing the exact esptool command used for flashing. It includes alternative invocations via idf.py flash, idf.py -p PORT flash, a direct python -m esptool command, and a command using the @flash_args file from the build directory. ```text Project build complete. To flash, run: idf.py flash or idf.py -p PORT flash or python -m esptool --chip esp32 -b 460800 --before default-reset --after hard-reset write-flash --flash-mode dio --flash-size 2MB --flash-freq 40m 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin 0x10000 build/hello_world.bin or from the "esp-idf/examples/get-started/hello_world/build" directory python -m esptool --chip esp32 -b 460800 --before default-reset --after hard-reset write-flash "@flash_args" ``` -------------------------------- ### espefuse get-custom-mac command and output Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/get-custom-mac-cmd.html Run the espefuse get-custom-mac command to print the Custom MAC Address. The output shows the command prompt, the command execution banner, and the resulting Custom MAC Address with its version and CRC status. ```text > espefuse get-custom-mac === Run "get-custom-mac" command === Custom MAC Address version 1: 48:63:92:15:72:16 (CRC 0x75 OK) ``` -------------------------------- ### New espefuse public API replacement for execute-scripts Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/migration-guide.html Shows the recommended replacement using the public API with init_commands, batch_mode, and do_not_confirm. The batch_mode argument is required to avoid burning eFuses one by one, which was the previous default behavior of execute-scripts. ```python from espefuse import init_commands with init_commands(port="/dev/ttyUSB0", batch_mode=True, do_not_confirm=True) as espefuse: espefuse.burn_efuse({"JTAG_DISABLE": "1", "DISABLE_SDIO_HOST": "1", "CONSOLE_DEBUG_DISABLE": "1"}) with open("../../images/efuse/256bit", "rb") as f: espefuse.burn_key(["flash_encryption"], [f], no_protect_key=True) with open("../../secure_images/rsa_secure_boot_signing_key.pem", "rb") as f: espefuse.burn_key_digest([f]) espefuse.burn_bit("BLOCK3", [64, 66, 69, 72, 78, 82, 83, 90]) espefuse.burn_custom_mac(b"\xaa\xbb\xcc\xdd\xee\x88") espefuse.burn_all() espefuse.summary() espefuse.adc_info() espefuse.get_custom_mac() if not espefuse.efuses["BLOCK1"].is_readable() or not espefuse.efuses["BLOCK1"].is_writeable(): raise Exception("BLOCK1 should be readable and writeable") ``` -------------------------------- ### HSM config file (hsm_config.ini) Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espsecure/index.html Sample HSM config file for SoftHSMv2. Required fields: pkcs11_lib, credentials, slot, label, label_pubkey. The credentials field stores the plaintext User PIN to automate signing. ```ini # hsm_config.ini # Config file for the external Hardware Security Module # to be used to generate signature. [hsm_config] # PKCS11 shared object/library module of the HSM vendor pkcs11_lib = /usr/local/lib/softhsm/libsofthsm2.so # HSM login credentials credentials = 1234 # Slot number to be used slot = 1108821954 # Label of the object used to store the private key label = Private Key for Digital Signature # Label of the object used to store corresponding public key # label_pubkey is the same as label if the label for public key # is not explicitly specified while key-pair generation. label_pubkey = Public Key for Digital Signature ``` -------------------------------- ### Classic reset sequence (D0|R1|W0.1|D1|R0|W0.05|D0) Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/configuration-file.html Shows the Python equivalent of the classic reset sequence defined by `D0|R1|W0.1|D1|R0|W0.05|D0`. The sequence toggles DTR and RTS lines with sleeps to enter and exit the bootloader. Note that the signal representation is for an Espressif devkit and may differ on other boards. ```python _setDTR(False) # BOOT=HIGH _setRTS(True) # EN=LOW, chip in reset time.sleep(0.1) _setDTR(True) # BOOT=LOW _setRTS(False) # EN=HIGH, chip out of reset time.sleep(0.05) _setDTR(False) # BOOT=HIGH, done ``` -------------------------------- ### Run espefuse tests in virtual mode Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/contributing.html Command format for test_espefuse.py, which tests espefuse functionality using the --virt virtual mode. Safe to run without hardware, but do not run on real hardware as it risks damaging the chip. ```bash pytest test_espefuse.py --chip ``` -------------------------------- ### Generate UF2 merged binary with esptool merge-bin Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html Use this command to generate a UF2 binary from multiple firmware files. The resulting file can be copied to a USB mass storage device exposed by an ESP running the ESP USB Bridge project. Gaps between files are filled with 0x00 bytes. ```bash esptool --chip ESP32 merge-bin --format uf2 -o merged-flash.uf2 --flash-mode dio --flash-size 4MB 0x1000 bootloader.bin 0x8000 partition-table.bin 0x10000 app.bin ``` -------------------------------- ### Enable verbose output with --verbose Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/advanced-options.html Use the --verbose or -v flag to display all output without overwriting or collapsing stages. ```bash esptool --verbose flash-id ``` -------------------------------- ### espefuse.init_commands Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/scripting.html Initializes the ESP eFuse commands class for a given chip, establishing a connection and returning a BaseCommands instance with initialized chip and eFuse values. ```APIDOC ## espefuse.init_commands ### Description Get the ESP eFuse commands class for the given chip. This function will establish a connection to the chip and return the ESP eFuse commands class with initialized chip and eFuse values. ### Method Function call ### Endpoint `espefuse.init_commands(port: str | None = None, baud: int = 115200, before: str = 'default-reset', chip: str = 'auto', esp: ESPLoader | EmulateEfuseControllerBase | None = None, **kwargs: Any) -> BaseCommands` ### Parameters - **port** (str | None) - Optional - The port to connect to the chip - **baud** (int) - Optional - The baud rate to connect to the chip - **before** (str) - Optional - The reset mode to use before connecting to the chip - **chip** (str) - Optional - The chip to use - **esp** (ESPLoader | EmulateEfuseControllerBase | None) - Optional - Optional ESPLoader object to use. If provided, the port, baud, before, and chip arguments will be ignored. If provided, user has to take care of closing the port. ### Keyword Arguments - **skip_connect** (bool) - Optional - Whether to skip connecting to the chip. Default is False. - **virt** (bool) - Optional - Whether to use virtual mode. Default is False. - **debug** (bool) - Optional - Whether to enable debug mode. Default is False. - **virt_efuse_file** (str) - Optional - The file to save the eFuse values to. Default is None. - **do_not_confirm** (bool) - Optional - Whether to skip confirmation before burning eFuse. Default is False. - **extend_efuse_table** (str) - Optional - The file to extend the eFuse table from. Default is None. - **batch_mode** (bool) - Optional - Whether to enable batch mode. Default is False. ### Returns - **BaseCommands** - The ESP eFuse commands class ``` -------------------------------- ### Fast reflash with partial diff-with files Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/basic-commands.html Provide fewer --diff-with files than the total number of binaries to selectively fast reflash only the initial files in the sequence. ```bash esptool write-flash 0x1000 bootloader.bin 0x10000 app.bin 0x20000 assets.bin --diff-with old_boot.bin ``` -------------------------------- ### espefuse burn-key-digest usage and output Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/burn-key-digest-cmd.html Shows the command to burn a Secure Boot V2 key digest from a PEM file, followed by the command's output including the confirmation prompt and final summary. The key is burned to BLOCK2 and the operation is irreversible. ```text > espefuse burn-key-digest secure_boot_key_v2_0.pem === Run "burn-key-digest" command === Sensitive data will be hidden (see --show-sensitive-info) - BLOCK2 -> [?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??] Disabling write to efuse BLOCK2... Check all blocks for burn... idx, BLOCK_NAME, Conclusion [00] BLOCK0 is empty, will burn the new value [02] BLOCK2 is empty, will burn the new value . This is an irreversible operation! Type 'BURN' (all capitals) to continue. BURN BURN BLOCK2 - OK (write block == read block) BURN BLOCK0 - OK (write block == read block) Reading updated efuses... Successful > espefuse summary ... BLOCK2 (BLOCK2): Secure boot key = a2 cd 39 85 df 00 d7 95 07 0f f6 7c 8b ab e1 7d 39 11 95 c4 5b 37 6e 7b f0 ec 04 5e 36 30 02 5d R/- ``` -------------------------------- ### Writing binary files with high-level commands Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/esptool/scripting.html Uses the public API to connect, run the stub flasher, attach flash, write two binary files, and reset the chip. The esp object is used as a context manager to ensure proper port closure. ```python from esptool.cmds import connect_esp, attach_flash, reset_chip, run_stub, write_flash BOOTLOADER = "bootloader.bin" FIRMWARE = "firmware.bin" with connect_esp() as esp: # Auto-discover the port and detect the chip esp = run_stub(esp) # Skip this line to avoid running the stub flasher attach_flash(esp) # Attach the flash memory chip, required for flash operations with open(BOOTLOADER, "rb") as bl_file, open(FIRMWARE, "rb") as fw_file: write_flash(esp, [(0, bl_file), (0x1000, fw_file)]) # Write the binary files reset_chip(esp, "hard-reset") # Reset the chip ``` -------------------------------- ### Run espefuse adc-info command Source: https://docs.espressif.com/projects/esptool/en/latest/esp32/espefuse/adc-info-cmd.html Executes the adc-info command to retrieve and display the ADC VRef calibration value from eFuse. ```bash > espefuse adc-info === Run "adc-info" command === ADC VRef calibration: 1121mV ```