# Understanding the Safeboot Partition Scheme for Tasmota Factory Images in ESP Flasher

> Safeboot partition scheme explained. ESP Flasher simplifies Tasmota factory image flashing by automatically deploying the safeboot recovery firmware for ESP32 devices.

- Repository: [Jason2866/esp_flasher](https://github.com/jason2866/esp_flasher)
- Tags: deep-dive
- Published: 2026-03-04

---

**The safeboot partition scheme reserves offset `0x10000` for a minimal recovery firmware that allows ESP32 devices to recover from corrupted user flashes, which ESP Flasher automatically detects and deploys by downloading the appropriate safeboot binary from the Tasmota OTA server and flashing it alongside the bootloader, partition table, and user firmware.**

Tasmota v13+ introduced a robust safeboot partition layout for ESP32-class devices to prevent devices from becoming unrecoverable after failed over-the-air updates. The **jason2866/esp_flasher** repository implements automated handling of this scheme, detecting chip variants and orchestrating multi-partition flashes without manual intervention. This article examines how the safeboot partition scheme works and how ESP Flasher manages it for Tasmota factory images.

## What Is the Safeboot Partition Scheme?

The **safeboot partition scheme** splits the firmware across distinct regions instead of using a single monolithic image. The layout reserves specific offsets for critical components:

| Offset | Content | Purpose |
|--------|---------|---------|
| `0x0000` | Bootloader | Initial boot code (may be 0 B on some chips) |
| `0x8000` | Partition table | Defines flash organization |
| `0xe000` | OTA data (`otadata.bin`) | Over-the-air update state |
| **0x10000** | **Safeboot factory image** | Minimal recovery bootloader |
| `0xe0000` | User firmware | Primary Tasmota application |

The **safeboot binary** at `0x10000` contains a minimal environment capable of re-flashing the user firmware region if a standard OTA update corrupts the primary firmware. This dual-partition approach ensures devices remain recoverable even when the main `0xe0000` region contains invalid code.

## How ESP Flasher Automates Safeboot Deployment

ESP Flasher handles the entire safeboot workflow automatically, from chip detection to coordinated flashing. The implementation resides primarily in [`esp_flasher/common.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/common.py).

### Detecting Factory Images via Magic Bytes

The tool determines whether a supplied binary is a factory image by inspecting offset `0x10000` for the ESP image magic. In [`esp_flasher/common.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/common.py), the `read_firmware_info` function performs this check between lines 189-197:

```python
def read_firmware_info(firmware):
    firmware.seek(0x10000)                # Check for safeboot image

    header = firmware.read(4)
    magic, _, flash_mode_raw, flash_size_freq = struct.unpack("BBBB", header)
    if magic == esptool.ESPLoader.ESP_IMAGE_MAGIC:
        # Factory (safeboot) image found

        ...

```

When the magic byte matches `esptool.ESPLoader.ESP_IMAGE_MAGIC`, the function sets `flag_factory = True`, triggering the safeboot flash path.

### Selecting Chip-Specific Safeboot Binaries

For regular (non-factory) images, `configure_write_flash_args` identifies the ESP32 variant and selects the corresponding safeboot file. Lines 269-322 in [`common.py`](https://github.com/jason2866/esp_flasher/blob/main/common.py) implement this logic:

```python
if "ESP32-C2" in info.model:
    model = "esp32c2"
    safeboot = "tasmota32c2-safeboot.bin"
elif "ESP32-C3" in info.model:
    model = "esp32c3"
    safeboot = "tasmota32c3-safeboot.bin"
...
elif "ESP32-P4" in info.model:
    # Special handling for revision 3.0+

    ...
    safeboot = "tasmota32p4rev3-safeboot.bin"
else:
    model = "esp32"
    safeboot = "tasmota32solo1-safeboot.bin"

```

This ensures the safeboot binary matches the specific silicon revision and capabilities of the target device.

### Downloading from the Tasmota OTA Server

If no custom safeboot file is provided via `--safeboot`, ESP Flasher constructs the download URL automatically. The constant `ESP32_SAFEBOOT_SERVER` defined in [`esp_flasher/const.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/const.py) (lines 17-20) points to the official Tasmota OTA host:

```python
if not factory_firm_path:
    factory_firm_path = ESP32_SAFEBOOT_SERVER + safeboot

```

The `open_downloadable_binary` function (lines 21-40 in [`common.py`](https://github.com/jason2866/esp_flasher/blob/main/common.py)) handles the actual HTTP retrieval, allowing transparent use of remote URLs without manual downloading.

### Coordinating Multi-Partition Flash Writes

The tool hard-codes the critical offsets for the safeboot layout in lines 264-268 of [`common.py`](https://github.com/jason2866/esp_flasher/blob/main/common.py):

```python
ofs_partitions   = 0x8000
ofs_otadata      = 0xe000
ofs_factory_firm = 0x10000
ofs_firmware     = 0xe0000

```

During the flash preparation phase, `configure_write_flash_args` assembles these into an address-filename list passed to `esptool`. Lines 375-380 append each component:

```python
addr_filename.append((ofs_bootloader, bootloader))
addr_filename.append((ofs_partitions, partitions))
addr_filename.append((ofs_otadata, otadata))
addr_filename.append((ofs_factory_firm, factory_firm))
addr_filename.append((ofs_firmware, firmware))

```

`esptool.write_flash` receives this list and writes all five components to their respective offsets in a single operation.

## Flashing Tasmota with Safeboot Support

ESP Flasher requires no manual partition table editing to deploy safeboot images. The following command automatically downloads the correct safeboot binary for the detected chip and flashes the complete set:

```bash
esp_flasher \
    --port /dev/ttyUSB0 \
    --firmware tasmota32.bin \
    --bootloader auto \
    --partitions auto \
    --otadata auto

```

To override the automatic download with a locally patched safeboot binary, use the `--safeboot` flag:

```bash
esp_flasher \
    --port /dev/ttyUSB0 \
    --firmware tasmota32.bin \
    --safeboot ./custom-safeboot.bin \
    --bootloader auto \
    --partitions auto \
    --otadata auto

```

## Summary

- The **safeboot partition scheme** places a recovery bootloader at offset `0x10000` to enable firmware recovery from corrupted user flashes at `0xe0000`.
- **ESP Flasher** detects safeboot images by checking for ESP image magic bytes at `0x10000` via `read_firmware_info` in [`esp_flasher/common.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/common.py).
- The tool automatically selects chip-specific safeboot binaries (e.g., `tasmota32c3-safeboot.bin`) based on the detected ESP32 model.
- Safeboot binaries download automatically from the Tasmota OTA server defined in [`esp_flasher/const.py`](https://github.com/jason2866/esp_flasher/blob/main/esp_flasher/const.py) unless overridden by the `--safeboot` argument.
- All components—bootloader, partition table, otadata, safeboot, and user firmware—flash simultaneously using hard-coded offsets in a single `esptool` invocation.

## Frequently Asked Questions

### What happens if the safeboot partition is corrupted?

If the safeboot region at `0x10000` becomes corrupted, the device may lose the ability to recover automatically from a failed user firmware update. In this scenario, physical reflashing via USB/serial using ESP Flasher is required to restore the safeboot binary and partition table.

### Can I use ESP Flasher with non-Tasmota firmware that uses safeboot?

Yes, though ESP Flasher is optimized for Tasmota. You can supply any compatible safeboot binary using the `--safeboot` argument. The tool will flash it to offset `0x10000` according to the standard safeboot partition scheme, but you must ensure the binary is compatible with your specific ESP32 variant and partition table.

### Why does ESP Flasher check offset 0x10000 specifically for safeboot detection?

Offset `0x10000` is the standardized location for the factory/safeboot image in the Tasmota safeboot partition scheme. The `read_firmware_info` function seeks to this address to check for the ESP image magic (`ESPLoader.ESP_IMAGE_MAGIC`), distinguishing factory images from single-partition user firmware that typically starts at `0xe0000`.

### How does ESP Flasher handle ESP32-P4 revision-specific safeboot binaries?

For ESP32-P4 devices, the code in `configure_write_flash_args` (lines 269-322 of [`common.py`](https://github.com/jason2866/esp_flasher/blob/main/common.py)) includes special handling to identify silicon revision 3.0+. It selects `tasmota32p4rev3-safeboot.bin` for newer revisions and `tasmota32p4-safeboot.bin` for earlier silicon, ensuring compatibility with hardware-specific boot requirements.