Upgrading ESP32 bootloader wirelessly using esphome

I have a few ESP32 devices around the house that are hard to access for USB upgrades. When I got them, I did the setup using a pogo plug jig I cobbled together, expecting to do all further upgrades wirelessly. I knew I’d have to take them apart and find the jig to do any future USB update but didn’t expect to have to do that.

All worked to plan until I started getting this warning from esphome:

... Bootloader too old for OTA rollback and SRAM1 as IRAM (+40KB). Flash via USB once to update the bootloader

It seems that there’s no safe way to update the bootloader on an ESP32. Anything that interrupts the flash is likely leave it in a soft brick state and I’d have to flash it via USB. Hmm… so basically if the flash succeeds I’m done and if it fails I’m no worse off than I was in the first place. Sounds like it’s worth a try.

So how do I flash the bootloader wirelessly? There’s no option in the ESPHome Device Builder UI. The esphome documentation does show how to do it from the command line, https://esphome.io/components/ota/esphome/#updating-the-bootloader-on-esp32.1 Click through to read the documentation but I’ll paste the most important part here

Take that warning seriously. I was able to upgrade all four of my devices without incident but I can’t promise you’ll be as lucky. Don’t even think about doing this upgrade during a thunderstorm or if your power is flaky today. Maybe avoid running big downloads or torrents while the flash is in progress. The good news is that the bootloader flash is really fast so the window for things to fail is short.

So we’re looking at a 3 flash process:

  1. Flash once to enable allow_partition_access.
  2. Flash the bootloader via the command line.
  3. Flash again to disable allow_partition_access and enable sram1_as_iram.

In theory, you can do steps 1 and 3 using the UI but since you need to log into the esphome container anyway it’s just easier to do it all from the command line.

Add allow_partition_access your yaml file(s)

ota:
  - platform: esphome
    ...
    allow_partition_access: true

It’s worth a reminder that you should only use spaces for indentation, no tabs, and that indentation actually means something in YAML files. Make sure you line things up as shown.

(Thank you busman for pointing out what a mess my indentation was.)

Flash the device(s)

Log into your homeassistant instance

ssh homeassistant

Log into your esphome docker container

docker exec -it addon_5c53de3b_esphome /bin/bash

Flash this configuration

cd /config/esphome
esphome run your-device-file.yaml

Flash the bootloader

You should still be in the /config/esphome directory in the docker container. Remember. This is the dangerous step!!!

esphome upload --bootloader your-device-file.yaml

This should finish pretty quickly.

Check the logs (IMPORTANT)

esphome logs your-device-file.yaml

The only warning you should be seeing now is:

Bootloader supports SRAM1 as IRAM (+40KB). Set sram1_as_iram: true under esp32 > framework > advanced

Note that it must say Bootloader supports. That means you’ve successfully updated the bootloader and are ready to enable sram1_as_iram. If you don’t see that message and especially if you’re still seeing the Bootloader too old message STOP RIGHT HERE and retrace your steps. If you enable sram1_as_iram with an old bootloader you may brick your device.

Enable sram1_as_iram

Now that you’re running the latest bootloader which supports sram1_as_iram you can enable it. It goes under esp32>framework>advanced:

esp32:
  ...
  framework:
    ...
    advanced:
      ...
      sram1_as_iram: true

Also, remove the “allow_partition_access: true” that you previously added to the ota section – it’s safest to leave it enabled only when you want to update the bootloader via OTA.

One last flash

esphome run your-device-file.yaml

Check the log file. The warning should be gone.

Enjoy your fully updated ESP32 device, your up to date bootloader, the extra memory, and the safe OTA rollbacks that come with it.


  1. Interestingly, the --bootloader option is not documented along with the esphome upload command: https://esphome.io/guides/cli/#upload-command. I think the message is pretty clear that you’re on your own recovering in case of failure. ↩︎