Flash Shelly firmware
Suppose you have a Shelly device with a custom firmware (esphome, tasmota) or, like in my case, you just bought a couple of Shelly Plug S and you’re stuck with an old firmware which is not getting updates anymore.
There’s a way out of this. The old, reliable way. And it involves an usb to serial adapter.
Hardware connection
This step is very well documented on the web, just search for your device name on sites like Tasmota Supported Devices Repository or ESPHome Device Configuration Repository.
Software tool
You need the proper flashing tool for the job: ESPtool.
1pip install esptool
Acquiring the firmware
You may think that the best firmware source is the Official firmware Archive, but here you can’t find all the releases.
So you can turn to the official Shelly Support website, which is ugly to browse.
Another valuable tool is the Firmware Archive Generator: here you can generate a link to update a working shelly device with a specific firmware release.
For example, if you use 192.168.3.1
for a shelly plug s
and release 1.12
you get this link: http://192.168.33.1/ota?url=http://archive.shelly-tools.de/version/v1.12/SHPLG-S.zip
.
We can extract the URL of the firmware we need: http://archive.shelly-tools.de/version/v1.12/SHPLG-S.zip
, and download the corresponding ZIP archive.
Firmware contents
The ZIP archive contains some binary files and a json document.
The binary blobs (rboot.bin
, fs.bin
, shelly-plug-s.bin
, esp_init_data_default_v08.bin
) are the parts of the device’s firmware; imagine that as a very small operating system: you have a boot-loader, a filesystem, a device-specific software and configuration data.
Each of these parts is meant to be written to a specific location on the ESP flash memory.
A quick peek in the manifest.json
files reveals all:
1{
2 "build_id": "20220809-124506/v1.12-g99f7e0b",
3 "build_timestamp": "2022-08-09T12:45:06Z",
4 "name": "shelly-plug-s",
5 "parts": {
6 "boot": {
7 "addr": 0,
8 "cs_sha1": "2dfef208220da2cf0ad424f5a3cb560537222d23",
9 "cs_sha256": "ff89425505fcf82e9ad12096d7747f89a5bff3e8cbe3849a0b963daa9a775c94",
10 "size": 2320,
11 "src": "rboot.bin",
12 "update": false
13 },
14 "boot_cfg": {
15 "addr": 28672,
16 "fill": 255,
17 "size": 4096
18 },
19 "fs": {
20 "addr": 765952,
21 "addr1": 1814528,
22 "cs_sha1": "b6f4dffd644dc884012d4d027007c72ec50118be",
23 "cs_sha256": "7f416a3fa7647b4d26a4a3fce99685f958174ad5d388d758802e7bd162a357cd",
24 "fs_size": 262144,
25 "size": 262144,
26 "src": "fs.bin",
27 "type": "fs"
28 },
29 "fw": {
30 "addr": 32768,
31 "addr1": 1081344,
32 "cs_sha1": "658a48d01197821327a0056a533a8d2ec9a057f0",
33 "cs_sha256": "09f75b4c30d68cc7ff09681393017dfd3a071a09aa9de5b8a68c328d3e8785c6",
34 "size": 592800,
35 "src": "shelly-plug-s.bin"
36 },
37 "rf_cal_data": {
38 "addr": 2076672,
39 "fill": 255,
40 "size": 4096
41 },
42 "sys_params": {
43 "addr": 2080768,
44 "cs_sha1": "ff105e66b313201f5b40a2e02b7f00db24022088",
45 "cs_sha256": "b2218087cf938ce665b26ac049f7d146677c70fe2909205a4d0e6a58aef0e4b3",
46 "size": 128,
47 "src": "esp_init_data_default_v08.bin",
48 "type": "sys_params3"
49 }
50 },
51 "platform": "esp8266",
52 "version": "1.0"
53}
Simplified with some jq
wizardry:
1cat manifest.json | jq '.parts|map( select(.src)|{addr,src})'
1[
2 {
3 "addr": 0,
4 "src": "rboot.bin"
5 },
6 {
7 "addr": 765952,
8 "src": "fs.bin"
9 },
10 {
11 "addr": 32768,
12 "src": "shelly-plug-s.bin"
13 },
14 {
15 "addr": 2080768,
16 "src": "esp_init_data_default_v08.bin"
17 }
18]
We need the addresses in HEX notation, you can use bc
for that:
1echo "obase=16; 765952" | bc
Address | Address in hex | File |
---|---|---|
0 | 0 | rboot.bin |
765952 | BB000 | fs.bin |
32768 | 8000 | shelly-plug-s.bin |
2080768 | 1FC000 | esp_init_data_default_v08.bin |
Flashing
So the resulting command is:
1esptool -p /dev/ttyUSB0 --baud 115200 write_flash \
2 -fm dout --flash_freq 80m \
3 0x0 rboot.bin \
4 0xBB000 fs.bin \
5 0x8000 shelly-plug-s.bin \
6 0x1FC000 esp_init_data_default_v08.bin
Enjoy!