ESP32 Cam – OTA Uploading With Setup and Troubleshooting



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:

Make sure that you choose the correct partition scheme or else the uploading will fail

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.

Error uploading
Here is what happens if you fail to add the OTA code during WIFI uploading.

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

Leave a Reply

Your email address will not be published. Required fields are marked *