Guide - How to enable Wi-Fi OTA updates on ESP32-based Meshtastic boards
I suspect not a lot of people are using Meshtastic over Wi-Fi, since it was a little difficult to find the information I'm going to share here. I hope this guide saves someone the time I spent to figure it out.
Context
My main Meshtastic node is permanently installed up in the attic of our house, connected to Wi-Fi, and communicating with Home Assistant via this integration (plus some custom automations to handle receiving and sending messages). It all works very well, except for the fact I'm someone who likes keeping firmwares up-to-date on all my devices, and by default Meshtastic ships with support for OTA only over Bluetooth (which is disabled when Wi-Fi is active), meaning my only option for updating the firmware is to go up there, remove the damn thing and bring it to my desk to update it via serial.
Thankfully, the fine folk working on Meshtastic also provide an alternative OTA firmware for ESP32 devices that works over Wi-Fi, and completely solves my problem. Getting it to play ball, however, was not very straightforward...
Getting our hands dirty
We will be dicking around with partitions and whatnot, so before you attempt any of what's to follow, open the Meshtastic app and backup your configuration and keys! Just keep in mind the backup is plain-text and includes your Wi-Fi credentials, so do it on a device you trust.
Building the OTA firmware
Unfortunately, Meshtastic does not offer pre-compiled builds of this OTA firmware, so we have to compile it from source. 🙃
The instructions are very simple: clone the repo, cd
into it, then run:
$ pio run [-e <target>]
Easy peezy, right? Well, not so much. I ran into a number of errors trying to get it to build (system-managed Python libraries, errors about missing things that were actually installed, venv madness, etc), so here's a quick and dirty how-to:
- Clone the repo and
cd
to it. - Find which target you want to build (the
-e
parameter in the command). To do that, open theplatformio.ini
file and check which[env:...]
best matches your board. For my Heltec WSL v3, that isesp32s3
. - Spin up a temporary Docker container with Python:
$ docker run -it -v ./:/firmware python:3.13 bash
- Inside the container, install PlatformIO:
# curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py; python3 get-platformio.py
- Activate PlatformIO's venv:
# source /root/.platformio/penv/bin/activate
cd
to the firmware folder:# cd /firmware
- Run the build command. It will download a bunch of things and fail saying the Python library
rich
is not installed, but that's expected:# pio run -e esp32s3
- Install the library in the place the build process actually expects it to be:
# /root/.platformio/penv/.espidf-5.4.1/bin/pip install rich
- Run the build again, it should work now:
# pio run -e esp32s3
At the end you will see something along the lines of "Successfully created esp32s3 image". You can exit and destroy the container now, the firmware will be inside a hidden folder in the cloned git repo: .pio/build/esp32s3/firmware.bin
.
Figuring out the position of your device's OTA partition
We built the thing we needed in the previous step, now we need to figure out where to put it. Different devices have different flash storage sizes, and depending on the size, the "position" where we write the image also changes.
The easiest way to determine this is to have a look at the variants
folder in the main firmware's repo. Find the subfolder corresponding to your device, then inside it open the platformio.ini
file and check if it contains the following line:
board_build.partitions = default_8MB.csv
If it does, then your OTA partition offset (where it starts) is at 0x340000
, otherwise it will be 0x260000
. Remember this number!
Replacing the OTA partition
- Navigate to the folder where the
firmware.bin
file was created in the previous steps (<repo>/.pio/build/esp32s3/firmware.bin
). - Make sure you have
esptool.py
installed (Sorry, I won't cover that. This guide is already longer than it was in my head). - Connect your board via USB and run the following command to overwrite the OTA partition, replacing the part in bold with the partition offset from the previous section:
$ esptool.py -b 115200 write_flash 0x340000 firmware.bin
- Congratulations! This was the most annoying part, the rest is simpler.
Downloading and installing the newest Meshtastic build over the air
- Make sure you have the Meshtastic CLI tools installed.
- Save the
espota.py
script somewhere in your system's$PATH
and give it permission to be executed. - Make sure your computer and the board are connected to the same network. If in different networks, make sure the firewall is not blocking traffic between the two.
- Go to the releases page of the main Meshtastic firmware repo and download and extract the package compatible with your board. That is, for example,
firmware-esp32s3-2.6.12.9861e82.zip
in my case. - Navigate to the extracted folder in the terminal.
- Put your board in OTA mode by running:
$ meshtastic –-host <board's IP address or hostname> --reboot-ota
- After a few seconds, the board should reconnect to the same Wi-Fi network in OTA mode.
- Send the firmware update with:
$ espota.py -i <board's IP address or hostname> -f firmware-heltec-wsl-v3-2.6.10.9ce4455-update.bin
.
Make sure you select the file with -update
in the name, otherwise you will mess up your board.
That's it! To install other updates in the future, simply repeat this last section. The Wi-Fi OTA firmware will remain installed as long as you don't do a full re-flash on the board.