I’m having trouble uploading code to my Arduino Uno R4 WiFi using PlatformIO in Visual Studio Code with the Arduino OTA library. Here’s what I’ve observed.
I can reliably upload code to my Arduino Uno R4 WiFi over WiFi using the IP address with the Arduino IDE. This suggests that the network and device configuration are set up correctly.
When I use PlatformIO in VS Code, I can upload code successfully over a USB connection to the Arduino Uno R4 WiFi.
When I attempt to upload code over WiFi using PlatformIO by specifying the IP address (192.168.1.67) and the Arduino OTA library, the upload process initiates but then fails at the end with the error message: “No device at 192.168.1.67,” which is the target IP address I set.
I can ping the device ip and its host name in the same platformio terminal.
I don’t believe this is a network issue since the Arduino IDE works perfectly fine for WiFi uploads using the same setup. My goal is to keep everything within VS Code for a more streamlined workflow.
Has anyone encountered a similar issue or could offer some guidance on how to resolve this when using the Arduino OTA library with PlatformIO in VS Code? Any help or suggestions would be greatly appreciated!
No that’s still invoking the program for flashing something via USB; it can’t do the ArduinoOTA upload procedure.
You see that for the Arduino IDE 2 and the Renesas, you also had to copy a file with special instructions for the Arduino IDE 2 to invoke the arduinoOTA program.
You’re missing that part for PlatformIO completely. You need to at least get a copy of the arduinoOTA program (or a package that contains it), then modify use a upload_protocol = custom with an appropriate upload_command to invoke arduinoOTA, with the same parameters that the Arduino IDE 2 would do (this includes IP, password, username, etc.)
unmodified in the platformio.ini? You need to replace ip_address with the actual IP address here.
arduino is the username and password is the password used above. (“HTTP Basic Authentication”). Double check that these are the same values you use in your sketch. These are the default values…
Note that “Arduino” is not the username here but the advertised MDNS hostname.
with the already linked extra_script.py and a src/main.cpp of
#include <WiFiS3.h>
#include <ArduinoOTA.h>
#define SECRET_SSID "XXXXXXXXX"
#define SECRET_PASS "XXXXXXXXXXXX"
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password
int status = WL_IDLE_STATUS; // the WiFi radio's status
void printWifiStatus();
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
// while (!Serial) {
// wait for serial port to connect. Needed for native USB port only
//}
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true)
;
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 second for connection:
delay(10000);
}
// start the WiFi OTA library with internal (flash) based storage
// The IDE will prompt for this password during upload
ArduinoOTA.begin(WiFi.localIP(), "Arduino", "password", InternalStorage);
// you're connected now, so print out the status:
printWifiStatus();
pinMode(LED_BUILTIN, OUTPUT);
}
static unsigned long last_time = 0;
void loop() {
if(millis() - last_time >= 5000) {
printWifiStatus(); //sign of life
digitalWrite(LED_BUILTIN, digitalRead(LED_BUILTIN) ^ 1);
last_time = millis();
}
// check for WiFi OTA updates
ArduinoOTA.poll();
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
And upload works fine.
Also I just placed the needed curl.exe directly in the project folder, next to the platformio.ini.
One more thing. On my original Arduino script I have this code to signal a start of OTA. I actually get this message in the log, but it doesn’t actually load the script…
// OTA Setup
ArduinoOTA.onStart([]() {
// OTA update starting
printAll("Starting OTA update...");
});
Can you try it with my exact src/main.cpp from above but with just filled out SSID and Password strings? Upload it once via USB to get a good start (comment out all the upload_xx and extra_scripts stuff in the platformio.ini)
Yes, trying my best to do exactly that. I set it up again from scratch and followed the steps you just described.
The USB load worked great with the commented lines out. I then added them back in.
I was able to get your code to work over OTA today. I have no idea what I did differently but I suppose today I did something different than yesterday… (log shared below)
I then tried to load my code over OTA the same way with the same .ini and it failed (log shared below). So maybe somethings complex about my code? As a note, my OTA lines of code are identical so IDK.
Now I tried to “reset” this lab test back to try mimicking your files. So I reloaded your code via USB to get it ready. And over the OTA update after that I get:
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 62040 0 0 100 62040 0 769k --:--:-- --:--:-- --:--:-- 766k
curl: (56) Recv failure: Connection was reset
*** [upload] Error 56
.
.
This is the log from the first time I was able to load your code over OTA **and** I was able to then load my code in there via OTA.
Adding in wireshark just in case on the latest fail when trying to only load your code. I can’t figure out why I struggle getting the same result every time?
The behavior might differ with curl.exe and arduinoOTA.exe as uploader. Maybe curl sends the data too quickly for the ESP32 to handler.
I’ve also made sure that my sketch has a non-blockingloop(). So, nodelay() used such that ArduinoOTA.poll() is called as quickly as possible.
Also, the OTA only works with the firmware size is at most half of the flash size (of 256kB), since the Uno R4 stores the incoming firmware in the upper half of the flash.