Cut the Cord: How to Implement Over-The-Air (OTA) Updates on ESP8266

Cut the Cord: How to Implement Over-The-Air (OTA) Updates on ESP8266

CONTENTS.log
šŸ“‘ Table of Contents
Bill of Materials
QTY: 5
[1x]
NodeMCU (ESP8266)
SOURCE_LINK
[1x]
5mm LED Assortment
SOURCE_LINK
[5x]
Jumper Wires
SOURCE_LINK
[1x]
830-Point Breadboard
SOURCE_LINK
[1x]
Micro-USB Cable
SOURCE_LINK

* SYSTEM.NOTICE: Affiliate links support continued laboratory research.

Imagine you have installed a weather station on your roof. It is February. It is raining. You discover a bug in your code. Do you: A) Get the ladder, climb the slippery roof, unscrew the waterproof case, and plug in a USB cable? B) Sit on your couch, press ā€œUploadā€ in Arduino IDE, and watch the magic happen?

If you chose B, welcome to OTA (Over-The-Air) Updates. This is the difference between a ā€œHobbyist Projectā€ and a ā€œProfessional Productā€. Today, we will learn how to flash firmware wirelessly, secure it with passwords, and understand the deep memory mechanics that make it possible.

OTA Wireless Update Process

The Concept: How Does It Work?

Normally, the ESP8266 bootloader waits for a signal on the UART (Serial) pins to accept new code. With OTA, the logic changes:

  • The Code runs: The ESP8266 connects to WiFi.
  • The Code listens: It waits for a specific ā€œHandshakeā€ on port 8266.
  • The Trigger: The computer sends an update invitation.
  • The Download: The firmware is written to a separate partition.
  • The Swap: After reboot, the bootloader switches to the new partition.

The Magic of Partitions (Deep Dive)

Your ESP8266 (e.g., 4MB Flash) is not just one big bucket. It is sliced up.

  • Bootloader (0x0000): Runs first; decides which code to load.
  • App0 (Active): Your current running program.
  • App1 (OTA/Passive): Reserve space for the new firmware.
  • FS (LittleFS): Data and configuration storage.

When you do an OTA update, you are NOT overwriting App0. You are writing to App1. Only after a successful checksum verification does the Bootloader flip the switch to boot from App1 next time.

  • Safety: If the power cuts out halfway through the download, App0 is untouched. The device still boots.

Partition Table Visual

The Basic OTA Code

We use the standard ArduinoOTA library. It makes this process shockingly easy.

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char* ssid = "MyWiFi";
const char* password = "MyPassword";

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  // --- OTA CONFIGURATION ---
// Port defaults to 8266
  ArduinoOTA.setPort(8266);

  // Hostname defaults to esp8266-[ChipID]
  ArduinoOTA.setHostname("LivingRoom-Sensor");

  // No authentication by default
  // ArduinoOTA.setPassword("admin");

  // Define what happens during the update
  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_FS
      type = "filesystem";
    }
    // NOTE: if updating FS this would be the place to unmount FS using SPIFFS.end()
    Serial.println("Start updating " + type);
  });

  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });

  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });

  ArduinoOTA.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());
}

void loop() {
  // CRITICAL: You must call this frequently
  ArduinoOTA.handle(); 
// Your normal code goes here
}

The ā€œFirst Flashā€

There is a Catch-22. To update wirelessly, the code must already have OTA support. So, for the very first time, you must use the USB cable to upload this sketch. Once it is running:

  • Confirm the Serial Monitor shows a local IP.
  • Restart Arduino IDE to refresh network ports.
  • Select your device under Tools -> Port -> Network Ports.

Arduino IDE Network Port

Now, simply click Upload. The IDE will compile the code, find the ESP over the network, handshake, and blast the firmware over WiFi. Speed Note: It is often faster than USB (1MB/s vs 115200 baud).

Securing the Door

By default, anyone on your WiFi can upload code to your ESP. If you are at a Hackathon or a Coffee Shop, this is a disaster. Someone could upload a ā€œBrickā€ sketch or malware.

The Fix: Set a Password.

// Add this in setup()
ArduinoOTA.setPassword("SuperSecret123");

Now, when you click Upload in the IDE, a popup window will appear asking for the credentials.

  • Pro Tip: You can also use setPasswordHash if you don’t even want the plain text password in your compiled binary (preventing reverse engineering).

Password Auth Popup

Handling OTA Events

When an update starts, your device stops doing its main job.

  • If this is a light switch, blink an LED rapidly.
  • If this is a robot, stop all motors immediately.

The onStart Callback: This is where you make the device safe.

  • onStart: Stop motors and high-voltage relays.
  • LittleFS: Close all filesystem handles.
  • Feedback: Blink LEDs for visual progress.

The onProgress Callback: You can draw a progress bar on an OLED screen or Serial Monitor.

ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
  int percent = (progress / (total / 100));
  display.clearDisplay();
  display.setCursor(0,0);
  display.print("Updating: ");
  display.print(percent);
  display.print("%");
  display.display();
});

Serial Monitor Progress Bar

Understanding the ā€œCloneā€ Problem

When you upload via OTA, you are uploading the Currently Open Sketch. WARNING: If you upload a sketch that does not have the OTA code inside it, you permanently lose OTA capability. The next update will have to be via USB cable.

Best Practice: Create a ota_handler.h file. Include it in every single project you make. Never write the boilerplate again.

OTA Update Flowchart

What if the Update Fails? (The Brick)

  • WiFi Loss: If WiFi drops at 50%, the ESP detects the disconnection/timeout. It discards the half-written App1 partition and simply boots back into App0. Safe.

  • Power Loss: Same as above. The Bootloader Config isn’t updated until the very end.

  • Bad Code: You uploaded code that crashes immediately (WDT Reset).

This is the real danger. If the new code goes into a Reboot Loop, it never connects to WiFi, and you can’t OTA again.

  • The Fix: Implement a ā€œSafe Modeā€.

  • On Boot, check a pin. If logic is HIGH, enter a minimalist ā€œOTA Onlyā€ mode and skip the main application logic.

Bricked Device Graveyard

Advanced: HTTP Updates (The Netflix Model)

ArduinoOTA pushes code from your PC. But what if you want to update 1,000 devices deployed in customers’ homes? You can’t visit them all. The device must Pull updates from a server.

ESP8266httpUpdate Library:

  • The ESP checks a URL: http://myserver.com/firmware/version.json.

  • It sees a newer version exists.

  • It downloads the .bin file from the server.

  • It flashes itself.

#include <ESP8266httpUpdate.h>

void checkForUpdate() {
  t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://myserver.com/firmware.bin");

  switch (ret) {
    case HTTP_UPDATE_FAILED:
      Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
      break;
    case HTTP_UPDATE_NO_UPDATES:
      Serial.println("HTTP_UPDATE_NO_UPDATES");
      break;
    case HTTP_UPDATE_OK:
      Serial.println("HTTP_UPDATE_OK");
      break;
  }
}

HTTP Server Update Diagram

Partition Tables Explained

(Technical Deep Dive)

Why do you sometimes see ā€œ1MB (FS:64KB OTA:~470KB)ā€ in Arduino Tools? Because you need SPACE for the update.

  • Case 1: 4MB Flash (NodeMCU):

  • App0 (1MB): Current code.

  • App1 (1MB): Reserve update space.

  • FS (1MB): Filesystem storage.

  • WiFi (1MB): SDK settings and calibration.

  • Result: You can have huge code.

  • Case 2: 1MB Flash (ESP-01):

  • App0 (490KB): Max code size for OTA.

  • App1 (490KB): Clone space.

  • Result: Your code CANNOT be larger than 490KB, or OTA will fail (Not enough space to download the copy).

Tip: If OTA fails with ā€œNo Spaceā€, reduce your File System size in the Tools menu to free up Flash for the App.

Dual Bank Boot Mechanism

Bonus: Browser-Based OTA (The Router Interface)

What if you don’t have Arduino IDE? What if you want to update from your iPhone? You can run a mini Website on the ESP8266 that accepts a .bin file upload.

The Code:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>

ESP8266WebServer httpServer(80);
ESP8266HTTPUpdateServer httpUpdater;

void setup() {
  // ... WiFi Setup ...
// This adds the /update page
  httpUpdater.setup(&httpServer);
  httpServer.begin();
  Serial.println("HTTP Update Server Ready");
  Serial.printf("Open http://%s/update in your browser\n", WiFi.localIP().toString().c_str());
}

void loop() {
  httpServer.handleClient();
}

How to Use:

  • In Arduino IDE, go to Sketch -> Export Compiled Binary.

  • It creates a .bin file in your project folder.

  • Open http://192.168.1.X/update.

  • Drag and drop the .bin file.

  • Done. The device reboots with new code.

Glossary: The OTA Dictionary

  • Bootloader: Code that swaps partitions on boot.
  • Magic Byte: Identifier for valid compiled binary.
  • MD5 Checksum: Math verification for data integrity.
  • mDNS: Local device name discovery (.local).
  • Partition Map: The CSV defining flash allocation.

Final Project: The ā€œRemote Toggleā€

We will build a device that we never plug in again.

  • Step 1: Flash OTA-enabled sketch via USB.
  • Step 2: Change code (e.g., blink speed) and upload wirelessly.
  • Step 3: Watch the hardware update instantly.

Final Setup Photo No Cables

Copyright Ā© 2026 TechnoChips. Open Source Hardware (OSHW).

Comments