Shelly ESPhome OTA conversion Guide

Unfortunately unless someone with more EE skill than me wants to tackle it you might be best purchasing Gen2 dimmers.

Unfortunately pull request https://github.com/esphome/esphome/pull/5535 was closed and locked.

I suggest someone with an understanding of the problem opens a new issue at https://github.com/esphome/esphome/issues

@bdraco You recently merged ESPHome PR “Add extended OTA protocol”. Is it any easier now to flash ESPHome onto Shelly Gen4 devices? Can it be done via Tasmota? Can it be done directly?

I successfully OTAed ESPHome directly onto a Shelly Gen2 Plus Plug US.

See my comment on this thread for details, I will post a guide once I get all the features working for sure. Shelly being acquired by Schneider Electric - #32 by inventor7777

since v1.7+ (Gen3) verifies OTA images with an ECDSA signature using their private key.

It does indeed burn eFuse BLOCK3 when it detects custom firmware, but it still runs fine. I think it voids the warranty and maybe blocks cloud functions, however.

I got my FW 1.7.5 Gen2 Plus Plugs flashed seamlessly OTA with ESPHome.

I created a thread and repo for instructions. I’m sure the same principle could be applied to OTA other Shelly devices :thinking:

with Gen2 and ESP32-S yes. but not with the newer ESP32-C with Matter. they use ECDSA singd bins for OTA.

im more then open to flash one of your OTA bins on a Gen3 / Gen4 dev. just gimme a link and i will try. maybe you fond something we all missed.

" Shelly Duo Bulb E27 Gen3 " would be fun.

I refuse to take any responsibility for such a thing, as I cannot test any Gen3s :joy:

For Gen4, you could probably try this project:

I could try to reverse the fw on a Gen3 device and see if I could send you a test file but I am just not too confident.

the responsibility is on me.

thanks for the link, i will give it a try!

i have to admin, i was wrong!

Bulb Gen3 and Plug M Gen3

are OTA’ed! :heart::heart::heart:

finally.

[14:26:43]ESP-ROM:esp32c3-api1-20210207
[14:26:43]Build:Feb  7 2021
[14:26:43]rst:0x1 (POWERON),boot:0xd (SPI_FAST_FLASH_BOOT)
[14:26:43]SPIWP:0xee
[14:26:43]mode:DIO, clock div:1
[14:26:43]load:0x3fcd5820,len:0x1568
[14:26:43]load:0x403cbf10,len:0xc20
[14:26:43]load:0x403ce710,len:0x3084
[14:26:43]entry 0x403cbf1a

Awesome! What did you do for the Gen3s? My image only supports Gen2, and the other project only did Gen4?

the same you did. :call_me_hand:
create a custom ota.zip with the esphome.ota.bin inside.

you need to unplug the device for ~30sec, the capacitor can hold power for a while. otherwise Shelly will boot into stock fw. also you had to reboot the device ~3-4 times before the other Partition was selected.

the hint of gen4 with the partitions.csv and CONFIG_PARTITION_TABLE_OFFSET. was pure gold.

esp32:
  board: esp32-c3-devkitm-1
  variant: esp32c3
  flash_size: 8MB
  partitions: PlugMG3-stock.csv   # Shellys eigenes Layout, siehe Kommentar oben
  framework:
    type: esp-idf
    sdkconfig_options:
      # stock Shelly keeps the partition table at 0x10000, not IDF's default 0x8000.
      # without this the firmware installs but cannot find its partitions at boot.
      # see "The partition system" in README.md
      CONFIG_PARTITION_TABLE_OFFSET: "0x10000"

with that i could replace the bootloader and OTA runs as smooth as normal.

i have created a little script for all that..

usage: ota.py [-h] <command> ...

Pack an ESPHome app image into a Shelly Gen3 OTA ZIP.

Only the app part is replaced; the rest comes from the official Shelly ZIP.

options:
  -h, --help    show this help message and exit

commands:
  <command>
    list        show devices and cached firmware
    fetch       get the official firmware ZIP (downloads if missing)
    add-device  create a device profile from an official ZIP
    build       build an OTA ZIP from your app image
    send        send a ZIP to a Shelly (it downloads from this PC)
    restore     send the cached official firmware back to a Shelly
    log         show the live debug log of a Shelly
    clean       delete old ZIPs in out/ (shows what, needs --yes)
    inspect     show and verify an OTA ZIP

examples:
  python ota.py list
  python ota.py build PlugMG3 app.bin
  python ota.py build PlugMG3 app.bin --tag v2 --drop nvs
  python ota.py build PlugMG3 firmware.ota.bin --esphome-factory firmware.factory.bin   # recommended first install
  python ota.py send PlugMG3 out/PlugMG3-app-20261004.zip --watch 60
  python ota.py inspect out/PlugMG3-app-20261004.zip

Applying a built ZIP wipes NVS (Wi-Fi, settings) unless you --drop nvs.
Bootloader: by default Shelly's bootloader stays. --esphome-factory swaps in ESPHome's (and a clean otadata) so later
ESPHome OTAs work; confirmed on the Plug M Gen3 only, and if it does not suit a device only UART can recover it.
restore only works while the Shelly firmware still runs; a device already on ESPHome needs UART.
Details per command: python ota.py <command> -h

i have a some devices to test:

DuoBulbG3    Shelly Duo Bulb Gen3     slot=0x280000
    fw 2.0.1  20260923-075433/2.0.1-ge1a198b
PlugMG3      Shelly Plug M Gen3       slot=0x2a0000
    fw 2.0.1  20260923-075548/2.0.1-ge1a198b
PlugSG3      Shelly Plug S Gen3       slot=0x2a0000
    fw 2.0.1  20260923-075613/2.0.1-ge1a198b
PowerStrip   Shelly Power Strip 4 Gen4 slot=0x300000
    fw 2.0.1  20260923-075623/2.0.1-ge1a198b
PowerStripZB Shelly Power Strip 4 Gen4 (Zigbee) slot=0x300000
    fw 2.0.1  20260923-075610/2.0.1-ge1a198b
RGBCCTBulbG3 Shelly Multicolor Bulb E27 Gen3 slot=0x280000
    fw 2.0.1  20260923-075708/2.0.1-ge1a198b

i will test Gen4, and if i can get my hands on some old Gen2, i will try them as well.

but i only can test the EU-Version.

Fyi, the first topic in the thread is a wiki, meaning everyone can edit and update it…

If i have time I’ll check my 2 first attempts again.
They’re stuck on the version i flashed them with as all ota’s are rejected due to wrong partition table. Not very optimistic they will succeed; the damage is done and i think they can only be flashed by wire :confused:

(if only those soldering pads weren’t that small and fragile)

my english isn’t that good, so i don’t feel comfortable to write wikis and such.

rejected with the message? : E (60542) esp_ota_ops: ota data invalid, no current app. Assuming factory

i have tested more devices against the script.

Manufacturer Device Profile Package Chip Tested on hardware
Shelly Plug M Gen3 `PlugMG3` ESP32-C3 2.0.1 :white_check_mark: `send` from stock 1.8.99, then two ESPHome OTAs
Shelly Duo Bulb Gen3 `DuoBulbG3` ESP32-C3 2.0.1 not yet. The owner reports the same main board as the Multicolor Bulb with a different lamp module; its stock firmware has no I2C code (LED PWM instead), so the LED driver config of the Multicolor Bulb does not apply. The OTA chain should be the same, but it has not been run
Shelly Multicolor Bulb E27 Gen3 `RGBCCTBulbG3` ESP32-C3 2.0.1 :white_check_mark: `send` with `–esphome-factory` (installed loader 1.0.2, profile default raises it to 1.0.3) ran through and ESPHome runs (reported by the owner). The LED driver (KP18068, own component, config in the device branch) and the channel order were not confirmed yet
Shelly Plug S Gen3 `PlugSG3` ESP32-C3 2.0.1 :white_check_mark: `send` with `–esphome-factory` (profile default `boot_min_version`, one patch level above the official loader) ran and ESPHome runs (reported by the owner). The build was the base config without relay or metering
Shelly H&T Gen3 `HTG3` ESP32-C3 2.0.1 :white_check_mark: `send` from stock 2.0.1 (slot 0) with `–esphome-factory`: ESPHome’s bootloader is written (profile sets `boot_min_version 1.0.9`, the default 1.0.3 was skipped), ESPHome boots and ESPHome OTAs take effect. Partition table at `0xf000`, so `CONFIG_PARTITION_TABLE_OFFSET: “0xf000”`
Shelly Power Strip 4 Gen4 `PowerStrip` ESP32-C6 2.0.1 :white_check_mark: ESPHome boots and joins Wi-Fi/Home Assistant (UART log) with ESPHome’s bootloader (`boot_min_version 1.0.9`). From stock 1.7.99 a direct `send` did not work (app landed in slot 1, old app started); it worked after one official update to 2.0.1, see [Notes](#notes–troubleshooting). Outlets and metering not checked here
Shelly Plus Plug S (V2 hardware, Gen2) `PlusPlugS` ESP32 1.7.5 :white_check_mark: Without UART: `send` with `–esphome-factory` wrote ESPHome’s bootloader (installed loader was 1.0.2; the ESPHome build needs the 80 MHz flash header, otherwise `build` refuses). The installer first targeted slot 1, so `ota.py restore` came first (it put Shelly’s bootloader back), then `send` targeted slot 0, ESPHome booted, and an ESPHome OTA took effect (0.2.0 to 0.2.11); see Notes. A bricked unit was brought back to Shelly OS over UART first ([Recovery over UART](#recovery-over-uart))