Arduino OTA support is great for updating devices over wifi. However the Arduino IDE only detects devices on the same broadcast network. If you run your IoT devices in their own vlan, this can be a a problem.

However you can manually envoke an upload from the cli tools.

Preparation

This process is not exactly refined, so do a little research first.

  1. Build your project, taking note of the configured output location. You’re looking for the $myproject.ino.bin file.
  2. Find espota.py from the esp8266 package. In my case it was located in C:\Users\myuser\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.6.3\tools.
  3. Determine if there’s any firewall between your networks.

The OTA protocol & firewalls

An OTA upload actually has two steps to it, each using a different set of ports and protcols.

Initial exchange. This step can be considered a “push” of an update request to the arduino. A message is sent from your local computer to 8266/udp of the arduino, containing authentication and file transfer details. The transfer details contain a randomly choosen tcp port which the file exchange step will use.

File exchange. This step can be considered as the arduino “pulling” the new image down to itself. The arduino establishes a tcp connection to the random port on your local computer which was picked in the intial exchange.

This two step process can be significant if you run a firewall between these networks. The firewall will not see the intial exchange and the file exchange as being part of the same transaction. In the case of a locked-down IoT network it’s quite possible that your arduino device is not permitted to make random connections to other networks, and the file exchange step will fail.

To solve this you have to pick a file transfer port in advance, and ensure the firewall allows the arduino network to make tcp connections to your local network on that port.

In summary, you need to permit this traffic:

  • local network -> arduino network, dst 8266/udp
  • arduino network -> local network, dst $yourpick/tcp

Example

The arguments I use for espota.py are:

-i IP address of arduino device  <required>
-f the binary image to upload    <required>
-a authentication                <use if a password is set>
-P file transfer port            <use to solve firewall problems>
-d show debug information        <use for extra insight>
-p show upload progress          <use for extra insight>
PS C:\...\tools> python .\espota.py -i 10.10.1.1  -a "MyPassword" -d -r -P 18266 -f L:\build\myproject.ino.bin
13:16:23 [DEBUG]: Options: {'esp_ip': 10.10.1.1', 'host_ip': '0.0.0.0', 'esp_port': 8266, 'host_port': 18266, 'auth': 'MyPassword', 'image': 'L:\\build\\myproject.ino.bin', 'spiffs': False, 'debug': True, 'progress': True}
13:16:23 [INFO]: Starting on 0.0.0.0:18266
13:16:23 [INFO]: Upload size: 339280
13:16:23 [INFO]: Sending invitation to: 10.10.1.1
Authenticating...OK
13:16:23 [INFO]: Waiting for device...
Uploading: [============================================================] 100% Done...