Over-The-Air (OTA) & Multi-Network
The firmware allows wireless firmware flashing over your local Wi-Fi network or VPN, eliminating the need to physically access the ESP32 once mounted.
1. Zero-Attack-Surface Security Architecture
Leaving wireless update ports open 24/7 is a severe security vulnerability on IoT devices. The ESP32-SwitchBot solves this with gated access:
- Locked by Default: OTA port
3232is completely closed at boot. Port scans show closed/filtered. - Secret-Key Authentication: Unlocking requires submitting
OTA_KEYviaPOST /ota/enableor typing the passphrase in the cURL terminal dashboard. - 10-Minute Auto-Timeout: Once unlocked, the update window stays open for 10 minutes (
OTA_AUTO_TIMEOUT_MS = 600,000 ms). If no firmware upload is received, port 3232 automatically locks itself again.
2. Multi-Network & VPN Gotchas (-I <lan_ip>)
When invoking espota.py from a computer connected to multiple network interfaces (e.g., local Wi-Fi 192.168.1.2, Tailscale 100.x.x.x, Docker bridges, or corporate VPNs), uploads often fail with:
Uploading...................
[ERROR]: Error Uploading: [Errno 32] Broken pipeWhy This Occurs:
- Reverse Connection Handshake: Arduino/ESP32 OTA does not stream firmware purely through the outgoing command channel. Instead:
espota.pysends a UDP invitation packet to port 3232 on the ESP32.- The packet tells the ESP32: "I am ready, connect back to my IP to receive the binary stream."
- The ESP32 initiates an inbound reverse TCP connection back to the development host.
- Interface Ambiguity:
espota.pybinds to0.0.0.0by default and guesses which IP address to advertise to the ESP32. On machines with VPNs or Tailscale, it often mistakenly picks the virtual IP (100.x.x.xor172.17.x.x). - Unreachable Route: The ESP32 is on the physical local Wi-Fi (
192.168.1.0/24) and cannot route directly to the host's virtual interface. The reverse connection stalls and times out, triggering[Errno 32] Broken pipe.
The Solution: Use -I <lan_ip>
Always pass the capital -I flag specifying your computer's local physical LAN IP:
python3 components/arduino/tools/espota.py -i 192.168.1.50 -p 3232 -I 192.168.1.2 -f build/ESP32-SwitchBot.binThis binds espota.py to your physical local Wi-Fi adapter (192.168.1.2) and forces it to instruct the ESP32 to connect back to that exact local IP, ensuring a fast and reliable transfer.