I am supported by our readers and may earn a commission if you buy through our Affiliate Links at no cost to you. Thank you so much for your support. Read More
In this tutorial I’ll show you how to setup and troubleshoot OTA or Over The Air updating using Wifi and an ESP32 Cam.
The ESP32 does not have a serial port so this makes it difficult to update. I bought boards that have the FTDI Usb adapter built in, but they use all of the boards pins. So if I want to add connections such as Analog read and digital output, then I lose the ability to upload a sketch. Removing the board and re-attaching it to the shield is a cumbersome process that should be avoided if you can.
The solution is to use OTA updating and just send new code over Wifi.
Let’s see how this is done.
2 Methods To Use
There are two methods we can setup.
OTA Basic
OTA Web Updater
OTA Basic
Here we just create a wifi network and then a new network port is available right in the Arduino IDE. It’s quick and simple
OTA Web Updater
This method creates a web page that you can log onto. Once logged in, you upload a compiled binary file.
Setting Up The OTA Basic
Since this method is so quick and easy, we’ll do this first. Now the first time I tried this it failed so I’ll go over the issue and how you can solve this.
For this tutorial I’ll use the ESP32 Cam as discussed in tutorial Getting Started With Esp32 Cam
These are the boards I bought. Each as it’s own USB adapter that can be removed once you have setup the OTA Software.
In the Arduino IDE, setup your board and options as follows:
Board – AI Thinker ESP32-CAM
Partition Scheme – Minimal with OTA
Upload The Sketch
Navigate to ESP32 Examples and select the Basic OTA
Find these two lines in the sketch and enter in your ssid and password.
const char* ssid = “*******”;
const char* password = “*******”;
Chose the serial port and upload the sketch to your ESP32
You can also make your life easier by creating a unique name for your Network Port. I uncommented the second line and named mine myesp32AI-Thinker.
// Hostname defaults to esp3232-[MAC]
ArduinoOTA.setHostname(“myesp32AI-Thinker”);
Now open up the Tools and look down at the bottom under Network Ports. You should see something like this.
Uploading A New Sketch Using Wifi
Now you are ready to disconnect the board from your USB port. You can remove the FTDI adapter or the shield if you have one.
Supply power to the board and then go back to the Arduino IDE
Select the correct network port.
Upload the sketch.
For this example, I will just re-upload the original but you can add additional code as needed. If successful you should see something like this.
How To Add Custom Code
The whole point of this is to be able to add your own custom code. You might think you can simply open a new sketch and upload what you need, but that will only work the first time. The reason is that it will whipe out the OTA programming and you will have to reconnect it back to the USB in order to fix it.
The solution is to re-use the basic OTA code and add in your custom code as needed.
In the example below I will modify the Basic OTA code and add in a blink sketch.
/** * My Engineering Projects * * madscientistguy.com * * This code extends the example Basic OTA code to add a blinking LED capability */ #include <WiFi.h> #include <ESPmDNS.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> const char* ssid = "*****"; const char* password = "***"; //add our custom definition #define LED_PIN 2 unsigned long previousMillis = 0; // will store last time LED was updated const long interval = 500; // interval at which to blink (milliseconds) int ledState = LOW; // ledState used to set the LED void setup() { Serial.begin(115200); Serial.println("Booting"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } // Port defaults to 3232 // ArduinoOTA.setPort(3232); // Hostname defaults to esp3232-[MAC] ArduinoOTA.setHostname("myesp32-AI-Thinker"); // No authentication by default // ArduinoOTA.setPassword("admin"); // Password can be set with it's md5 value as well // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); ArduinoOTA .onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem"; // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() Serial.println("Start updating " + type); }) .onEnd([]() { Serial.println("\nEnd"); }) .onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println("Ready"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); /** Custom Code */ pinMode(LED_PIN, OUTPUT); } void loop() { ArduinoOTA.handle(); /** * Custom Code * */ //blink an led unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis; // if the LED is off turn it on and vice-versa: ledState = not(ledState); // set the LED with the ledState of the variable: digitalWrite(LED_PIN, ledState); } }
Troubleshooting
Network Unavailable
Notice in the example sketch that I did not use the delay() function. Delay pauses the program and this can cause issues when you want to update the code. If you happen to be uploading during the pause, you will get an error saying that the network in unavailable.
Try to avoid delay() and use some other method such as the time method that I used.
General Upload Error (just brackets with no response)
This error happened to me and it was difficult to find the solution. The error occurred when the partition scheme was incorrect.
Be sure to use the Minimal OTA scheme