8000
Skip to content

Read/Write bootloader, partition table and any partition via OTA - #5535

Closed
angelnu wants to merge 34 commits into
esphome:devfrom
angelnu:extend_ota
Closed

Read/Write bootloader, partition table and any partition via OTA#5535
angelnu wants to merge 34 commits into
esphome:devfrom
angelnu:extend_ota

Conversation

@angelnu
@angelnu angelnu commented Oct 15, 2023
Copy link
Copy Markdown
Contributor

What does this implement/fix?

This adds support to update the bootloader and partition tables with OTA. It allows migrating from
firmwares with different layouts (new Tasmota versions) or repair botloaders (such as the locked new Shellies).

Updating the bootloader and partition tables only works with the esp-idf framework. For arduino arduino-esp32 is needed. This is currently in alpha so no platformio package is available. It is possible to move from esp-idf to arduino OTA so you can migrate Tasmota -> esphome(esp-idf) -> esphome(arduino).

New CLI commands

# update OTA the bootloader without rebooting
python -m esphome -v upload test.yaml --bootloader --no-reboot
# update OTA the partition table without rebooting (requires esp32-idf version > 5.1)
python -m esphome -v upload test.yaml --partition-table --no-reboot
# update OTA partition with type and subtype
python -m esphome -v upload --partition-type=0x0 --partition-subtype=0x10 test.yaml
# update OTA partition with label
python -m esphome -v upload --partition-label=app0 test.yaml
# download OTA the bootloader
python -m esphome -v download test.yaml --bootloader --file=bootloader.bin
# download OTA the partition table without rebooting (requires esp32-idf version > 5.1)
python -m esphome -v download test.yaml --partition-table --file=partition_table.bin
# download OTA partition with type and subtype
python -m esphome -v download --partition-type=0x0 --partition-subtype=0x10 test.yaml  --file=firmware.bin
# download OTA partition with label
python -m esphome -v download --partition-label=app0 test.yaml  --file=firmware.bin
# update OTA all esphome parts (equivalent to a factory reset)
python -m esphome upload-factory-ota test.yaml

The upload-factory-ota command makes a backup of the partition table before flashing the new one. If any operation fails then the backup is automatically restored. This usually happens when the new firmware would override the running partition.

Tasmota migration

If you are migrating from Tasmota 1.12 or newer using the Safeboot partition you need the following steps. There are 2 options depending on the used esp-idf framework.

Single command (requires esp-idf>5.1)

This is how to do it without custom partition_tables.

  1. Build an ESPHome (test.yaml) with a minimal configuration (with wifi and OTA) with esp-idf>5.1
# Example for esp32-c3 (Shelly Plus 1PM Mini)
esphome:
  name: test
  platformio_options:
    board_build.flash_mode: dio
esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf
    platform_version: 6.4.0
    version: 5.1.1
  variant: esp32c3
wifi:
  manual_ip:
    static_ip: 192.168.0.33
    gateway: 192.168.2.1
    subnet: 255.255.192.0
    dns1: 192.168.2.1
  networks:
  - ssid: my_wifi
    password: my_wifi_password
ota:
  password: my_ota_password
  unprotected_writes: True # This is mandatory if you want to flash the partition table or bootloader!
logger:
  hardware_uart: USB_SERIAL_JTAG
web_server:
button:
- platform: restart
  name: Restart
  1. Use Tasmota firmware upgrade with the ESPHome legacy firmware binary built in the previous step. ESPHome should boot
  2. Upgrade all ESPHome to factory: python -m esphome -v upload-factory-ota test.yaml. ESPHome should reboot and use ESPHome partition table and boot loader.

Afterwards you might downgrade to the recommend esp-idf framework.

Using multiple commands

If you are using the recommend esp-idf framework you will need to use a custom partition table:

  1. Build an ESPHome (test.yaml) with a minimal configuration (with wifi and OTA) and the following partition table (this uses the Tasmota OTA data partition and app1 address/size):
# Name,   Type, SubType, Offset,   Size, Flags
otadata,  data, ota,     0x00e000,        0x2000,
# phy_init, data, phy,     ,        0x1000,
app0,     app,  ota_1,   0x010000,      0x0d0000,
app1,     app,  ota_0,   0x0e0000,      0x0d0000,
nvs,      data, nvs,     0x38C000,       0x6d000,
# Example for esp32-c3 (Shelly Plus 1PM Mini)
esphome:
  name: test
  platformio_options:
    board_build.partitions: "../../../custom_partitions.csv"
    board_build.flash_mode: dio
esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: esp-idf
  variant: esp32c3
wifi:
  manual_ip:
    static_ip: 192.168.0.33
    gateway: 192.168.2.1
    subnet: 255.255.192.0
    dns1: 192.168.2.1
  networks:
  - ssid: my_wifi
    password: my_wifi_password
ota:
  password: my_ota_password
  unprotected_writes: True # This is mandatory if you want to flash the partition table or bootloader!
logger:
  hardware_uart: USB_SERIAL_JTAG
web_server:
button:
- platform: restart
  name: Restart
  1. Use Tasmota firmware upgrade with the ESPHome legacy firmware binary built in the previous step. ESPHome should boot
  2. Upgrade the partition table: python -m esphome -v upload test.yaml --partition-table. ESPHome should reboot and still run from address 0x0e0000 as in Tasmota
  3. Upgrade the ESPHome (either using the dashboard or python -m esphome -v upload test.yaml). ESPHome should boot and it will be running out of the 0x010000 address as in regular ESPHome. At this point OTA works but in order to use all available flash we need the following steps.
  4. Build ESPHome (test.yaml) without the custom partition table from step 1
  5. Upgrade the partition table: python -m esphome -v upload test.yaml --partition-table

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Other

Related issue or feature (if applicable): NA
Pull request in esphome-docs with documentation (if applicable): esphome/esphome-docs#

Test Environment

  • ESP32
  • ESP32 IDF
  • ESP8266
  • RP2040

Example entry for config.yaml:

# Example config.yaml
ota:
  unprotected_writes: True # This is mandatory if you want to flash the partition table or bootloader!
  password: removedPassword

Checklist:

  • The code change is tested and works locally.
  • Tests have been added to verify that the new code works (under tests/ folder).

If user exposed functionality or configuration variables are added/changed:

@angelnu angelnu changed the title add support to OTA the bootloader and partition table Support changing the bootloader and partition table via OTA Oct 15, 2023
@angelnu angelnu changed the title Support changing the bootloader and partition table via OTA Write bootloader, partition table and any partition via OTA Oct 22, 2023
@angelnu
angelnu marked this pull request as ready for review October 22, 2023 08:55
@angelnu
angelnu requested a review from a team as a code owner October 22, 2023 08:55
@probot-esphome
Copy link
Copy Markdown

Hey there @esphome/core, mind taking a look at this pull request as it has been labeled with an integration (ota) you are listed as a code owner for? Thanks!
(message by CodeOwnersMention)

@mbrevda
mbrevda commented Apr 15, 2025
Copy link
Copy Markdown

Perfect, thanks! After the above, I ran python -m esphome -v upload test.yaml --file path/to/file.bin to upload the firmware from HA's esphome instance, and it worked perfectly. Thanks again!

Hoping this can be merged soon...

@schildbach
Copy link
Copy Markdown

Thanks to this PR, I manged to migrate the last of my Tasmota 14.6 devices (an ESP32 Sonoff M5-3C) to ESPHome.

@lotharbach
lotharbach commented May 19, 2025
Copy link
Copy Markdown

The commands from #5535 (comment) were super helpful to start to figure things out for me, but I found I could simplify the python venv parts quite a bit:

# get a copy of angelnu's branch
git clone https://github.com/angelnu/esphome-1.git --branch=extend_ota
cd esphome-1/

# create a new python "virtual environment" into the folder "venv"
python3 -m venv venv

# use the python venv instead of your system wide python, you need to rerun this for every new shell
source venv/bin/activate

# install esphome requirements into venv
python -m pip install -r requirements.txt

# the content of test.yaml is highly dependent on your target device, edit with caution
vi test.yaml

# create the firmware.bin file
python -m esphome compile test.yaml

# tasmota ota/firmware update with esphome-1/.esphome/build/test/.pioenvs/test/firmware.bin
# after esphome has booted, perform final partition table/bootloader change
python -m esphome -v upload-factory-ota test.yaml

@tabascoz
tabascoz commented Jul 2, 2025
Copy link
Copy Markdown

@angelnu thanks for the PR and @lotharbach thanks for the summary of instructions. I installed in around 5 tasmotas v15. The only issue i had was the update through tasmota webpage was getting reset in the middle - perhaps something related to v15. I was able to continue by hosting the firmware in a local webserver.

@Cossid
Cossid commented Jul 16, 2025
Copy link
Copy Markdown
Contributor

@angelnu - Would it be possible to do a merge and resolve conflicts? It would be wonderful to see this make some progress towards actually being merged, as instructing to use a (possibly outdated) external PR component isn't a very smooth process.

@rwalker777
Copy link
Copy Markdown
Contributor

With the 2025.7.0 release lots of devices can no longer be upgraded without conversion to esp-idf. If @angelnu can't resolve conflicts, can someone else pick this up?

@ssieb
ssieb commented Jul 17, 2025
Copy link
Copy Markdown
Member

With the 2025.7.0 release lots of devices can no longer be upgraded without conversion to esp-idf. If @angelnu can't resolve conflicts, can someone else pick this up?

You can switch to esp-idf OTA. There's no problem. It won't change the partition table, but that's fine.

@Qhilm
Qhilm commented Jul 18, 2025
Copy link
Copy Markdown

Did you test this? I tested this (last year) and in Home Assistant it looks like it's successful but the device reloads into the old version simply, because partitions haven't been modified.

@bdraco
bdraco commented Jul 18, 2025
Copy link
Copy Markdown
Member

We have consolidated all the ota code into a single place in 2025.7 so it should be a bit easier to do now if someone wants to pick this up

@andrewjswan
Copy link
Copy Markdown
Contributor

I support it, it would be very convenient if this part was completed and included in ESPHome.

@andrewjswan
Copy link
Copy Markdown
Contributor

You can switch to esp-idf OTA. There's no problem. It won't change the partition table, but that's fine.

I tried switching from Arduino to IDF, 5 attempts, the firmware uploads without problems, but then it rolls back to 2025.6.3. I think this PR would solve this problem.

@andreas-bulling
Copy link
Copy Markdown

Same here - this feature would be super useful for a LOT of people!

@Bascht74
Copy link
Copy Markdown

Yes, +1 for this feature. Some devices are pain in the a… to use serial Flash. I used it to Switch to ESPIDF for some of my devices.

maybe this could be a start get even a bigger thing going Like Tasmota did start with V12 in 2022:

https://tasmota.github.io/docs/Safeboot/#introducing-safeboot

arendst/Tasmota#15500

That way even bigger ESPHome projects are possible…

@andrewjswan
Copy link
Copy Markdown
Contributor

The commands from #5535 (comment) were super helpful to start to figure things out for me, but I found I could simplify the python venv parts quite a bit

In which version of ESPHome did this work?

@carnei-ro
Copy link
Copy Markdown

tested with Sonoff MiniR4 Extreme with Tasmota v15 and Sonoff Dual R3 with Tasmota v14.2; Both worked great! Thanks for it ❀️

@andrewjswan
Copy link
Copy Markdown
Contributor
< 10BC8 /div>

tested with Sonoff MiniR4 Extreme with Tasmota v15 and Sonoff Dual R3 with Tasmota v14.2; Both worked great! Thanks for it ❀️

What version of ESP Home?

@carnei-ro
Copy link
Copy Markdown

tested with Sonoff MiniR4 Extreme with Tasmota v15 and Sonoff Dual R3 with Tasmota v14.2; Both worked great! Thanks for it ❀️

What version of ESP Home?

The version from this branch… then you can upgrade to the latest ESPHome version; just create your YAML with wifi.use_address configured with the IP of your Tasmota to EspHome converted device.

@andrewjswan
Copy link
Copy Markdown
Contributor

The version from this branch…

What version of ESPHome is in this branch? This branch does not work on 2025.7.

@andrewjswan
Copy link
Copy Markdown
Contributor

then you can upgrade to the latest ESPHome version; just create your YAML with wifi.use_address configured with the IP of your Tasmota to EspHome converted device.

I already have ESPHome flashed in Nous A8T, now I need to update the partition layout in it.

@grobius
grobius commented Aug 6, 2025
Copy link
Copy Markdown

I've tested the simplified steps by @lotharbach on a Shelly Plug Plus S that's running Tasmota 15.1. Unfortunately a only get to SafeBoot everytime I try to flash the firmware.bin through the Tasmota UI.

I guess I need to throw in the towel an open the damn device, but since Shelly Plugs now are worse than fort knox I'd like to make sure I've ruled out all posibilities to OTA.

Anyone have any suggestion?

@Snowdrop7209
Copy link
Copy Markdown

I've tested the simplified steps by @lotharbach on a Shelly Plug Plus S that's running Tasmota 15.1. Unfortunately a only get to SafeBoot everytime I try to flash the firmware.bin through the Tasmota UI.

I guess I need to throw in the towel an open the damn device, but since Shelly Plugs now are worse than fort knox I'd like to make sure I've ruled out all posibilities to OTA.

Anyone have any suggestion?

damn, that doesn't sound good.

I just bought 8 of these "Shelly Plug Plus S", then went ahead and flashed Tasmota and even used the auto config resize partition because i haven't read all the comments before.
It worked well with Tasmota and once I dropped a bin via OTA (used an LXC container version of ESPHOME made for Proxmox) then i just lost all details.
I get the logs, it even connects to the wifi, but no sensor data and I cannot control nor flash it.

========================= [SUCCESS] Took 16.98 seconds =========================
INFO Successfully compiled program.
INFO Connecting to 10.10.50.169 port 3232...
INFO Connected to 10.10.50.169
INFO Uploading /config/.esphome/build/shelly/.pioenvs/shelly/firmware.bin (943136 bytes)
ERROR Error binary size: Unknown error from ESP

I am able to view the logs via ESPHOME:

INFO ESPHome 2025.7.5
INFO Reading configuration /config/shelly.yaml...
INFO Detected timezone 'Etc/UTC'
INFO Starting log output from 10.10.50.169 using esphome API
INFO Successfully resolved shelly @ 10.10.50.169 in 0.000s
INFO Successfully connected to shelly @ 10.10.50.169 in 0.005s
INFO Successful handshake with tasmota-77574c-5964 @ 10.10.50.169 in 0.681s
[22:44:56][I][app:149]: ESPHome version 2025.7.5 compiled on Aug  7 2025, 20:49:28
[22:44:56][C][wifi:613]: WiFi:
[22:44:56][C][wifi:434]:   Local MAC: D4:8A:FC:77:57:4C
[22:44:56][C][wifi:439]:   SSID: [redacted]
[22:44:56][C][wifi:442]:   IP Address: 10.10.50.169
[22:44:56][C][wifi:446]:   BSSID: [redacted]
[22:44:56][C][wifi:446]:   Hostname: 'tasmota-77574c-5964'
[22:44:56][C][wifi:446]:   Signal strength: -54 dB β–‚β–„β–†β–ˆ
[22:44:56][C][wifi:455]:   Channel: 6
[22:44:56][C][wifi:455]:   Subnet: 255.255.255.0
[22:44:56][C][wifi:455]:   Gateway: 10.10.50.1
[22:44:56][C][wifi:455]:   DNS1: 10.10.50.1
[22:44:56][C][wifi:455]:   DNS2: 0.0.0.0
[22:44:56][C][logger:246]: Logger:
[22:44:56][C][logger:246]:   Max Level: DEBUG
[22:44:56][C][logger:246]:   Initial Level: DEBUG
[22:44:57][C][logger:252]:   Log Baud Rate: 115200
[22:44:57][C][logger:252]:   Hardware UART: UART0
[22:44:57][C][logger:259]:   Task Log Buffer Size: 768
[22:44:57][C][captive_portal:099]: Captive Portal:
[22:44:57][C][esphome.ota:073]: Over-The-Air updates:
[22:44:57][C][esphome.ota:073]:   Address: tasmota-77574c-5964.local:3232
[22:44:57][C][esphome.ota:073]:   Version: 2
[22:44:57][C][esphome.ota:080]:   Password configured
[22:44:57][C][safe_mode:018]: Safe Mode:
[22:44:57][C][safe_mode:019]:   Boot considered successful after 60 seconds
[22:44:57][C][safe_mode:019]:   Invoke after 10 boot attempts
[22:44:57][C][safe_mode:019]:   Remain for 300 seconds
[22:44:57][C][web_server.ota:224]: Web Server OTA
[22:44:57][C][api:207]: API Server:
[22:44:57][C][api:207]:   Address: tasmota-77574c-5964.local:6053
[22:44:57][C][api:212]:   Using noise encryption: YES
[22:44:57][C][mdns:122]: mDNS:
[22:44:57][C][mdns:122]:   Hostname: tasmota-77574c-5964

Not sure how can I recover from this.
The "unprotected_writes" option doesn't work, the ota platform needs to be set and the 2 options will always conflict with eachother.

@Snowdrop7209
Copy link
Copy Markdown

I've tested the simplified steps by @lotharbach on a Shelly Plug Plus S that's running Tasmota 15.1. Unfortunately a only get to SafeBoot everytime I try to flash the firmware.bin through the Tasmota UI.
I guess I need to throw in the towel an open the damn device, but since Shelly Plugs now are worse than fort knox I'd like to make sure I've ruled out all posibilities to OTA.
Anyone have any suggestion?

damn, that doesn't sound good.

I just bought 8 of these "Shelly Plug Plus S", then went ahead and flashed Tasmota and even used the auto config resize partition because i haven't read all the comments before. It worked well with Tasmota and once I dropped a bin via OTA (used an LXC container version of ESPHOME made for Proxmox) then i just lost all details. I get the logs, it even connects to the wifi, but no sensor data and I cannot control nor flash it.

========================= [SUCCESS] Took 16.98 seconds =========================
INFO Successfully compiled program.
INFO Connecting to 10.10.50.169 port 3232...
INFO Connected to 10.10.50.169
INFO Uploading /config/.esphome/build/shelly/.pioenvs/shelly/firmware.bin (943136 bytes)
ERROR Error binary size: Unknown error from ESP

I am able to view the logs via ESPHOME:

INFO ESPHome 2025.7.5
INFO Reading configuration /config/shelly.yaml...
INFO Detected timezone 'Etc/UTC'
INFO Starting log output from 10.10.50.169 using esphome API
INFO Successfully resolved shelly @ 10.10.50.169 in 0.000s
INFO Successfully connected to shelly @ 10.10.50.169 in 0.005s
INFO Successful handshake with tasmota-77574c-5964 @ 10.10.50.169 in 0.681s
[22:44:56][I][app:149]: ESPHome version 2025.7.5 compiled on Aug  7 2025, 20:49:28
[22:44:56][C][wifi:613]: WiFi:
[22:44:56][C][wifi:434]:   Local MAC: D4:8A:FC:77:57:4C
[22:44:56][C][wifi:439]:   SSID: [redacted]
[22:44:56][C][wifi:442]:   IP Address: 10.10.50.169
[22:44:56][C][wifi:446]:   BSSID: [redacted]
[22:44:56][C][wifi:446]:   Hostname: 'tasmota-77574c-5964'
[22:44:56][C][wifi:446]:   Signal strength: -54 dB β–‚β–„β–†β–ˆ
[22:44:56][C][wifi:455]:   Channel: 6
[22:44:56][C][wifi:455]:   Subnet: 255.255.255.0
[22:44:56][C][wifi:455]:   Gateway: 10.10.50.1
[22:44:56][C][wifi:455]:   DNS1: 10.10.50.1
[22:44:56][C][wifi:455]:   DNS2: 0.0.0.0
[22:44:56][C][logger:246]: Logger:
[22:44:56][C][logger:246]:   Max Level: DEBUG
[22:44:56][C][logger:246]:   Initial Level: DEBUG
[22:44:57][C][logger:252]:   Log Baud Rate: 115200
[22:44:57][C][logger:252]:   Hardware UART: UART0
[22:44:57][C][logger:259]:   Task Log Buffer Size: 768
[22:44:57][C][captive_portal:099]: Captive Portal:
[22:44:57][C][esphome.ota:073]: Over-The-Air updates:
[22:44:57][C][esphome.ota:073]:   Address: tasmota-77574c-5964.local:3232
[22:44:57][C][esphome.ota:073]:   Version: 2
[22:44:57][C][esphome.ota:080]:   Password configured
[22:44:57][C][safe_mode:018]: Safe Mode:
[22:44:57][C][safe_mode:019]:   Boot considered successful after 60 seconds
[22:44:57][C][safe_mode:019]:   Invoke after 10 boot attempts
[22:44:57][C][safe_mode:019]:   Remain for 300 seconds
[22:44:57][C][web_server.ota:224]: Web Server OTA
[22:44:57][C][api:207]: API Server:
[22:44:57][C][api:207]:   Address: tasmota-77574c-5964.local:6053
[22:44:57][C][api:212]:   Using noise encryption: YES
[22:44:57][C][mdns:122]: mDNS:
[22:44:57][C][mdns:122]:   Hostname: tasmota-77574c-5964

Not sure how can I recover from this. The "unprotected_writes" option doesn't work, the ota platform needs to be set and the 2 options will always conflict with eachother.

Just a quick update on this one:

I was able to compile a test.yaml with the following:

esphome:
  name: shelly
  platformio_options:
    board_build.partitions: "/custom_partitions.csv"
    board_build.flash_mode: dio

esp32:
  board: esp32doit-devkit-v1
  framework:
    type: esp-idf
    platform_version: 6.4.0
    version: 5.1.1
wifi:
  manual_ip:
    static_ip: 10.10.50.169
    gateway: 10.10.50.1
    subnet: 255.255.0.0
    dns1: 10.10.50.1
  networks:
  - ssid: "xxx"
    password: "xxx"

ota:
  password: "xxx"
  unprotected_writes: True # This is mandatory if you want to flash the partition table or bootloader!

logger:
  #hardware_uart: USB_SERIAL_JTAG
  hardware_uart: UART0

web_server:

button:
- platform: restart
  name: Restart

then I tried to flash it, but no luck, not sure which version I need to upgrade to for the OTA v2 support:

((venv) ) root@docker-desktop:/home/esphome-1# python3 -m esphome -v upload test.yaml --file /home/esphome-1/.esphome/build/shelly/.pioenvs/shelly/firmware-factory.bin
INFO ESPHome 2024.1.0-dev
INFO Reading configuration test.yaml...
WARNING The selected ESP-IDF framework version is not the recommended one. If there are connectivity or build issues please remove the manual version.
WARNING The selected ESP-IDF framework version is not the recommended one. If there are connectivity or build issues please remove the manual version.
INFO Connecting to 10.10.50.169
ERROR Unsupported OTA version 2
((venv) ) root@docker-desktop:/home/esphome-1#

@Najihel
Najihel commented Aug 7, 2025
Copy link
Copy Markdown

I've tested the simplified steps by @lotharbach on a Shelly Plug Plus S that's running Tasmota 15.1. Unfortunately a only get to SafeBoot everytime I try to flash the firmware.bin through the Tasmota UI.
I guess I need to throw in the towel an open the damn device, but since Shelly Plugs now are worse than fort knox I'd like to make sure I've ruled out all posibilities to OTA.
Anyone have any suggestion?

damn, that doesn't sound good.

I just bought 8 of these "Shelly Plug Plus S", then went ahead and flashed Tasmota and even used the auto config resize partition because i haven't read all the comments before. It worked well with Tasmota and once I dropped a bin via OTA (used an LXC container version of ESPHOME made for Proxmox) then i just lost all details. I get the logs, it even connects to the wifi, but no sensor data and I cannot control nor flash it.

========================= [SUCCESS] Took 16.98 seconds =========================
INFO Successfully compiled program.
INFO Connecting to 10.10.50.169 port 3232...
INFO Connected to 10.10.50.169
INFO Uploading /config/.esphome/build/shelly/.pioenvs/shelly/firmware.bin (943136 bytes)
ERROR Error binary size: Unknown error from ESP

I am able to view the logs via ESPHOME:

INFO ESPHome 2025.7.5
INFO Reading configuration /config/shelly.yaml...
INFO Detected timezone 'Etc/UTC'
INFO Starting log output from 10.10.50.169 using esphome API
INFO Successfully resolved shelly @ 10.10.50.169 in 0.000s
INFO Successfully connected to shelly @ 10.10.50.169 in 0.005s
INFO Successful handshake with tasmota-77574c-5964 @ 10.10.50.169 in 0.681s
[22:44:56][I][app:149]: ESPHome version 2025.7.5 compiled on Aug  7 2025, 20:49:28
[22:44:56][C][wifi:613]: WiFi:
[22:44:56][C][wifi:434]:   Local MAC: D4:8A:FC:77:57:4C
[22:44:56][C][wifi:439]:   SSID: [redacted]
[22:44:56][C][wifi:442]:   IP Address: 10.10.50.169
[22:44:56][C][wifi:446]:   BSSID: [redacted]
[22:44:56][C][wifi:446]:   Hostname: 'tasmota-77574c-5964'
[22:44:56][C][wifi:446]:   Signal strength: -54 dB β–‚β–„β–†β–ˆ
[22:44:56][C][wifi:455]:   Channel: 6
[22:44:56][C][wifi:455]:   Subnet: 255.255.255.0
[22:44:56][C][wifi:455]:   Gateway: 10.10.50.1
[22:44:56][C][wifi:455]:   DNS1: 10.10.50.1
[22:44:56][C][wifi:455]:   DNS2: 0.0.0.0
[22:44:56][C][logger:246]: Logger:
[22:44:56][C][logger:246]:   Max Level: DEBUG
[22:44:56][C][logger:246]:   Initial Level: DEBUG
[22:44:57][C][logger:252]:   Log Baud Rate: 115200
[22:44:57][C][logger:252]:   Hardware UART: UART0
[22:44:57][C][logger:259]:   Task Log Buffer Size: 768
[22:44:57][C][captive_portal:099]: Captive Portal:
[22:44:57][C][esphome.ota:073]: Over-The-Air updates:
[22:44:57][C][esphome.ota:073]:   Address: tasmota-77574c-5964.local:3232
[22:44:57][C][esphome.ota:073]:   Version: 2
[22:44:57][C][esphome.ota:080]:   Password configured
[22:44:57][C][safe_mode:018]: Safe Mode:
[22:44:57][C][safe_mode:019]:   Boot considered successful after 60 seconds
[22:44:57][C][safe_mode:019]:   Invoke after 10 boot attempts
[22:44:57][C][safe_mode:019]:   Remain for 300 seconds
[22:44:57][C][web_server.ota:224]: Web Server OTA
[22:44:57][C][api:207]: API Server:
[22:44:57][C][api:207]:   Address: tasmota-77574c-5964.local:6053
[22:44:57][C][api:212]:   Using noise encryption: YES
[22:44:57][C][mdns:122]: mDNS:
[22:44:57][C][mdns:122]:   Hostname: tasmota-77574c-5964

Not sure how can I recover from this. The "unprotected_writes" option doesn't work, the ota platform needs to be set and the 2 options will always conflict with eachother.

Just a quick update on this one:

I was able to compile a test.yaml with the following:

esphome:
  name: shelly
  platformio_options:
    board_build.partitions: "/custom_partitions.csv"
    board_build.flash_mode: dio

esp32:
  board: esp32doit-devkit-v1
  framework:
    type: esp-idf
    platform_version: 6.4.0
    version: 5.1.1
wifi:
  manual_ip:
    static_ip: 10.10.50.169
    gateway: 10.10.50.1
    subnet: 255.255.0.0
    dns1: 10.10.50.1
  networks:
  - ssid: "xxx"
    password: "xxx"

ota:
  password: "xxx"
  unprotected_writes: True # This is mandatory if you want to flash the partition table or bootloader!

logger:
  #hardware_uart: USB_SERIAL_JTAG
  hardware_uart: UART0

web_server:

button:
- platform: restart
  name: Restart

then I tried to flash it, but no luck, not sure which version I need to upgrade to for the OTA v2 support:

((venv) ) root@docker-desktop:/home/esphome-1# python3 -m esphome -v upload test.yaml --file /home/esphome-1/.esphome/build/shelly/.pioenvs/shelly/firmware-factory.bin
INFO ESPHome 2024.1.0-dev
INFO Reading configuration test.yaml...
WARNING The selected ESP-IDF framework version is not the recommended one. If there are connectivity or build issues please remove the manual version.
WARNING The selected ESP-IDF framework version is not the recommended one. If there are connectivity or build issues please remove the manual version.
INFO Connecting to 10.10.50.169
ERROR Unsupported OTA version 2
((venv) ) root@docker-desktop:/home/esphome-1#

Hi,

I have the same issue with my NsPanel.

@edwardtfn
Copy link
Copy Markdown
Contributor

I have the same issue with my NsPanel.

The NSPanel is quite easy to take from the wall and flash via serial/USB

@Najihel
Najihel commented Aug 8, 2025
Copy link
Copy Markdown

I have the same issue with my NsPanel.

The NSPanel is quite easy to take from the wall and flash via serial/USB

Unfortunately serial pads are broken on mine =(

@bdraco
bdraco commented Dec 1, 2025
Copy link
Copy Markdown
Member

Thank you @angelnu for this excellent work! This PR tackles a genuinely difficult problem - enabling bootloader and partition table updates over OTA is incredibly valuable for migrating devices from other firmwares and repairing locked bootloaders without serial access.

The community response here speaks volumes - the number of users who have successfully migrated Sonoff and Shelly devices using your branch demonstrates that the core approach is solid.

Unfortunately, we need to close this PR for a few reasons:

  1. Significant merge conflicts - The codebase has evolved substantially since this was opened, and the conflicts have grown to the point where resolving them would essentially require reimplementing portions of the PR.

  2. Extended inactivity - With no recent updates to address the conflicts or review feedback, it's become difficult to move forward.

  3. Blocking other efforts - Keeping this open in its current state can discourage others from attempting their own implementation, since it appears work is already in progress.

We're closing this to clear the path for someone else to pick up where you left off. The work here provides an excellent foundation and reference for anyone who wants to tackle this feature in the future - the implementation approach, the edge cases discovered, and the real-world testing feedback from the community are all invaluable.

If anyone is interested in continuing this effort, this PR is a great starting point to understand the scope and challenges involved.

Thanks again for the contribution!

@bdraco bdraco closed this Dec 1, 2025
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 3, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0