ArduinoOTA over the internet
ArduinoOTA is the easiest way to update an ESP32 without a cable, as long as the board is on the same network as your computer. Once it moves to a workshop, a client or a field, it stops working.
Why it only works at home
The Arduino IDE finds the board through mDNS, which does not leave the local network. Typing the IP address skips the search, but not the real obstacle: when the upload starts, the IDE sends an invitation to the board on UDP port 3232, and the board then opens a TCP connection back to your computer to fetch the image. Both sides have to reach each other. With the board behind one router and your computer behind another, neither can.
The ways around it
- A VPN. Put the board and your computer in the same private network, and ArduinoOTA works as it does at home. It needs a VPN server or a service, and a client on the board or a computer next to it.
- The board fetches the update. The sketch checks a URL now and then and downloads a new
.binwithHTTPUpdate. That needs a server for the images, a way to tell a board that there is a new one, and the RAM for a TLS connection while it downloads. - The update comes down a connection the board already holds. If the board keeps one connection open to a server, the image can be sent down it when you decide. That is what Pinscope does: upload the
.binin the dashboard and press Update firmware.
With Pinscope, step by step
Install the Pinscope library from the Library Manager and start it in setup(), after WiFi.begin():
#include <pinscope.h>
pinscope_config_t config = {};
config.project_key = "psk_..."; // Connect a device, in the dashboard
config.firmware_version = "1.0.1"; // raise it with each build
pinscope_start(&config);
Then, for each update:
- In the Arduino IDE, Sketch → Export Compiled Binary. In Arduino IDE 2 the files land in the sketch's folder under
build/<board>/. The one to send is<sketch>.ino.bin, not.merged.binor.bootloader.bin. - In the dashboard, upload it under Firmware, and press Update firmware on the device.
- The board writes it to its second app slot, checks it and restarts into it. The dashboard shows the new version once it is back.
The partition scheme needs two app slots. The default one has them; Huge APP and No OTA do not. With PlatformIO the file is .pio/build/<env>/firmware.bin.
If the new firmware cannot connect
A wrong WiFi password or a crash at start leaves a board that nobody can reach, and at home that means a cable. In the field it means a trip. The ESP32 bootloader in the Arduino core can go back to the previous firmware, but the core accepts every new firmware as soon as it boots. One line in the sketch changes that:
extern "C" bool verifyRollbackLater() { return true; }
The new firmware then stays on trial until it reaches Pinscope. If it has not after five minutes, the board restarts, and the bootloader goes back to the firmware it had before.
Two more things worth doing before the board leaves your desk: keep Pinscope in every build you send, or the board cannot be reached after the update, and try one update with a wrong WiFi password on purpose, to see the board come back.
Try it
Three devices are free, and no card is needed. Create an account, or read the five-minute guide first.
More
- Remote access to an ESP32 without TLS: what it measured and what it costs
- Reaching an ESP32 web server from outside its network
- Updating ESP32 firmware over the internet, with rollback
- Crash backtraces from devices in the field
- Remote logging: ESP_LOG without a serial cable
- Heap and stack monitoring in the field
- An ESP32 behind CGNAT, 4G or Starlink
- TLS memory usage on the ESP32, and how to reduce it
- Sharing an ESP32 sensor page with anyone, without port forwarding
- ESP32 remote access compared: port forwarding, ngrok, Cloudflare Tunnel, Tailscale
- esp_http_server slow? The 250 ms delay and the fix
- Before the first ESP32 ships: a field support checklist