ESP32 OTA (Over-the-Air) Updates - AsyncElegantOTA Arduino
Maybe your like
In this guide, you’ll learn how to do over-the-air (OTA) updates to your ESP32 boards using the AsyncElegantOTA library. This library creates a web server that allows you to upload new firmware (a new sketch) to your board without the need to make a serial connection between the ESP32 and your computer.
This tutorial is DEPRECATED. Please follow this instead: ESP32 OTA (Over-the-Air) Updates – ElegantOTA Library with Arduino IDE.
Additionally, with this library, you can also upload new files to the ESP32 filesystem (SPIFFS). The library is very easy to use, and it’s compatible with the ESPAsyncWebServer library that we often use to build web server projects.

By the end of this tutorial, you’ll be able to easily add OTA capabilities to your web server projects with the ESP32 to upload new firmware and files to the filesystem wirelessly in the future.
We have a similar tutorial for the ESP8266 NodeMCU board: ESP8266 NodeMCU OTA (Over-the-Air) Updates – AsyncElegantOTA using Arduino IDE
Watch the Video Tutorial
This project is available in video format and in written format. You can watch the video below or you can scroll down for the written instructions.
Overview
This tutorial covers:
- Add the ElegantOTA feature to your web server
- Upload new firmware via OTA to ESP32 board
- Upload files to SPIFFS via OTA to ESP32 board
We recommend that you follow all the tutorial steps to understand how ElegantOTA works and how you can use it in your projects. To demonstrate how to do this, we’ll upload files to build different web server projects.
ESP32 OTA (Over-the-Air) Programming
OTA (Over-the-Air) update is the process of loading new firmware to the ESP32 board using a Wi-Fi connection rather than a serial communication. This functionality is extremely useful in case of no physical access to the ESP32 board.
There are different ways to perform OTA updates. In this tutorial, we’ll cover how to do that using the AsyncElegantOTA library. In our opinion, this is one of the best and easiest ways to perform OTA updates.
The AsyncElegantOTA library creates a web server that you can access on your local network to upload new firmware or files to the filesystem (SPIFFS). The files you upload should be in .bin format. We’ll show you later in the tutorial how to convert your files to .bin format.

The only disadvantage of OTA programming is that you need to add the code for OTA in every sketch you upload so that you’re able to use OTA in the future. In the case of the AsyncElegantOTA library, it consists of just three lines of code.
AsyncElegantOTA Library
As mentioned previously, there are a bunch of alternatives for OTA programming with the ESP32 boards. For example, in the Arduino IDE, under the Examples folder, there is the BasicOTA example (that never worked well for us); the OTA Web Updater (works well, but it isn’t easy to integrate with web servers using the ESPAsyncWebServer library); and many other examples from different libraries.
Most of our web server projects with the ESP32 use the ESPAsyncWebServer library. So, we wanted a solution that was compatible with that library. The AsyncElegantOTA library is just perfect for what we want:

- It is compatible with the ESPAsyncWebServer library;
- You just need to add three lines of code to add OTA capabilities to your “regular” Async Web Server;
- It allows you to update not only new firmware to the board but also files to the ESP32 filesystem (SPIFFS);
- It provides a beautiful and modern web server interface;
- It works extremely well.
If you like this library and you’ll use it in your projects, consider supporting the developer’s work.
OTA Updates with AsyncElegantOTA Library – Quick Summary
To add OTA capabilities to your projects using the AsyncElegantOTA library, follow these steps:
- Install AsyncElegantOTA, AsyncTCP, and ESPAsyncWebServer libraries;
- Include AsyncElegantOTA library at the top of the Arduino sketch: #include <AsyncElegantOTA.h>;
- Add this line AsyncElegantOTA.begin(&server); before server.begin();
- Open your browser and go to http://<IPAddress>/update, where <IPAddress> is your ESP32 IP address.
Continue reading the tutorial for more detailed steps.
How does OTA Web Updater Work?
- The first sketch should be uploaded via serial port. This sketch should contain the code to create the OTA Web Updater so that you are able to upload code later using your browser.
- The OTA Web Updater sketch creates a web server you can access to upload a new sketch via web browser.
- Then, you need to implement OTA routines in every sketch you upload so that you’re able to do the next updates/uploads over-the-air.
- If you upload a code without an OTA routine, you’ll no longer be able to access the web server and upload a new sketch over-the-air.
Install AsyncElegantOTA Library
In this tutorial, the ESP32 will be programmed using Arduino IDE. If you want to learn how to do the same using VS Code + PlatformIO, follow the next tutorial: ESP32 OTA (Over-the-Air) Updates – AsyncElegantOTA (VS Code + PlatformIO)
You can install the AsyncElegantOTA library using the Arduino Library Manager. In your Arduino IDE, go to Sketch > Include Library > Manage Libraries… Search for “AsyncElegantOTA” and install it.

Install AsyncTCP and ESPAsyncWebServer Libraries
You also need to install the AsyncTCP and the ESPAsyncWebServer libraries. Click the links below to download the libraries.
- ESPAsyncWebServer
- AsyncTCP
These libraries aren’t available to install through the Arduino Library Manager, so you need to copy the library files to the Arduino Installation Libraries folder. Alternatively, in your Arduino IDE, you can go to Sketch > Include Library > Add .zip Library and select the libraries you’ve just downloaded.
AsyncElegantOTA ESP32 Basic Example
Let’s start with the basic example provided by the library. This example creates a simple web server with the ESP32. The root URL displays some text, and the /update URL displays the interface to update firmware and filesystem.
If you’re using an ESP32, you need to downgrade your ESP32 boards’ add-on to version 2.0.X. At the moment, the AsyncElegantOTA library is not compatible with version 3.X. If you want to use version 3.X, please use the newest version of the library: ElegantOTA V3.

Copy the following code to your Arduino IDE.
/* Rui Santos Complete project details - Arduino IDE: https://RandomNerdTutorials.com/esp32-ota-over-the-air-arduino/ - VS Code: https://RandomNerdTutorials.com/esp32-ota-over-the-air-vs-code/ This sketch shows a Basic example from the AsyncElegantOTA library: ESP32_Async_Demo https://github.com/ayushsharma82/AsyncElegantOTA */ #include <Arduino.h> #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include <AsyncElegantOTA.h> const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; AsyncWebServer server(80); void setup(void) { Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { request->send(200, "text/plain", "Hi! I am ESP32."); }); AsyncElegantOTA.begin(&server); // Start ElegantOTA server.begin(); Serial.println("HTTP server started"); } void loop(void) { }View raw code
Insert your network credentials and the code should work straight away:
const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD";How the Code Works
First, include the necessary libraries:
#include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include <AsyncElegantOTA.h>Insert your network credentials in the following variables so that the ESP32 can connect to your local network.
const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD";Create an AsyncWebServer object on port 80:
AsyncWebServer server(80);In the setup(), initialize the Serial Monitor:
Serial.begin(115200);Initialize Wi-Fi:
WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP());Then, handle the client requests. The following lines, send some text Hi! I am ESP32. when you access the root (/) URL:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { request->send(200, "text/plain", "Hi! I am ESP32."); });If your web server needs to handle more requests you can add them (we’ll show you in the next example).
Then, add the next line to start ElegantOTA:
AsyncElegantOTA.begin(&server);Finally, initialize the server:
server.begin();Access the Web Server
After uploading code to the board, open the Serial Monitor at a baud rate of 115200. Press the ESP32 on-board RST button. It should display the ESP IP address as follows (yours may be different):

In your local network, open your browser and type the ESP32 IP address. You should get access the root (/) web page with some text displayed.

Now, imagine that you want to modify your web server code. To do that via OTA, go to the ESP IP address followed by /update. The following web page should load.

Follow the next sections to learn how to upload new firmware using AsyncElegantOTA.
Upload New Firmware OTA (Over-the-Air) Updates – ESP32
Every file that you upload via OTA should be in .bin format. You can generate a .bin file from your sketch using the Arduino IDE.
With your sketch opened, you just need to go to Sketch > Export Compiled Binary. A .bin file will be generated from your sketch. The generated file will be saved under your project folder.
That’s that .bin file you should upload using the AsyncElegantOTA web page if you want to upload new firmware.
Upload a New Web Server Sketch – Example
Let’s see a practical example. Imagine that after uploading the previous sketch, you want to upload a new one that allows you to control an LED via a web interface like this project. Here’s the steps you need to follow:
1. Copy the following code to your Arduino IDE. Don’t forget to insert your network credentials.
/* Rui Santos Complete project details - Arduino IDE: https://RandomNerdTutorials.com/esp32-ota-over-the-air-arduino/ - VS Code: https://RandomNerdTutorials.com/esp32-ota-over-the-air-vs-code/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. */ // Import required libraries #include <Arduino.h> #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include <AsyncElegantOTA.h> // Replace with your network credentials const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; bool ledState = 0; const int ledPin = 2; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); AsyncWebSocket ws("/ws"); const char index_html[] PROGMEM = R"rawliteral( <!DOCTYPE HTML><html> <head> <title>ESP Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> <style> html { font-family: Arial, Helvetica, sans-serif; text-align: center; } h1 { font-size: 1.8rem; color: white; } h2{ font-size: 1.5rem; font-weight: bold; color: #143642; } .topnav { overflow: hidden; background-color: #143642; } body { margin: 0; } .content { padding: 30px; max-width: 600px; margin: 0 auto; } .card { background-color: #F8F7F9;; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); padding-top:10px; padding-bottom:20px; } .button { padding: 15px 50px; font-size: 24px; text-align: center; outline: none; color: #fff; background-color: #0f8b8d; border: none; border-radius: 5px; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: rgba(0,0,0,0); } /*.button:hover {background-color: #0f8b8d}*/ .button:active { background-color: #0f8b8d; box-shadow: 2 2px #CDCDCD; transform: translateY(2px); } .state { font-size: 1.5rem; color:#8c8c8c; font-weight: bold; } </style> <title>ESP Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" href="data:,"> </head> <body> <div class="topnav"> <h1>ESP WebSocket Server</h1> </div> <div class="content"> <div class="card"> <h2>Output - GPIO 2</h2> <p class="state">state: <span id="state">%STATE%</span></p> <p><button id="button" class="button">Toggle</button></p> </div> </div> <script> var gateway = `ws://${window.location.hostname}/ws`; var websocket; window.addEventListener('load', onLoad); function initWebSocket() { console.log('Trying to open a WebSocket connection...'); websocket = new WebSocket(gateway); websocket.onopen = onOpen; websocket.onclose = onClose; websocket.onmessage = onMessage; // <-- add this line } function onOpen(event) { console.log('Connection opened'); } function onClose(event) { console.log('Connection closed'); setTimeout(initWebSocket, 2000); } function onMessage(event) { var state; if (event.data == "1"){ state = "ON"; } else{ state = "OFF"; } document.getElementById('state').innerHTML = state; } function onLoad(event) { initWebSocket(); initButton(); } function initButton() { document.getElementById('button').addEventListener('click', toggle); } function toggle(){ websocket.send('toggle'); } </script> </body> </html>)rawliteral"; void notifyClients() { ws.textAll(String(ledState)); } void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) { AwsFrameInfo *info = (AwsFrameInfo*)arg; if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { data[len] = 0; if (strcmp((char*)data, "toggle") == 0) { ledState = !ledState; notifyClients(); } } } void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { switch (type) { case WS_EVT_CONNECT: Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); break; case WS_EVT_DISCONNECT: Serial.printf("WebSocket client #%u disconnected\n", client->id()); break; case WS_EVT_DATA: handleWebSocketMessage(arg, data, len); break; case WS_EVT_PONG: case WS_EVT_ERROR: break; } } void initWebSocket() { ws.onEvent(onEvent); server.addHandler(&ws); } String processor(const String& var){ Serial.println(var); if(var == "STATE"){ if (ledState){ return "ON"; } else{ return "OFF"; } } return String(); } void setup(){ // Serial port for debugging purposes Serial.begin(115200); pinMode(ledPin, OUTPUT); digitalWrite(ledPin, LOW); // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); } // Print ESP Local IP Address Serial.println(WiFi.localIP()); initWebSocket(); // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(200, "text/html", index_html, processor); }); // Start ElegantOTA AsyncElegantOTA.begin(&server); // Start server server.begin(); } void loop() { ws.cleanupClients(); digitalWrite(ledPin, ledState); }View raw code
This is the same code used in this project, but it contains the needed lines of code to handle ElegantOTA:
#include <AsyncElegantOTA.h> AsyncElegantOTA.begin(&server);2. Save your sketch: File > Save and give it a name. For example: Web_Server_LED_OTA_ESP32.
3. Generate a .bin file from your sketch. Go to Sketch > Export Compiled Binary. Several .bin files will be created under the project folder. You should upload the file with the ino.bin extension.
4. Now, you need to upload that file using the ElegantOTA page. Go to your ESP IP address followed by /update. Make sure you have the firmware option selected. Click on Choose File and select the .bin file you’ve just generated.

5. When it’s finished, click on the Back button.

6. Then, you can go to the root (/) URL to access the new web server. This is the page you should see when you access the ESP IP address on the root (/) URL.

You can click on the button to turn the ESP32 on-board LED on and off.

Because we’ve also added OTA capabilities to this new web server, we can upload a new sketch in the future if needed. You just need to go to the ESP32 IP address followed by /update.
Congratulations, you’ve uploaded new code to your ESP32 via Wi-Fi using AsyncElegantOTA.
Continue reading if you want to learn how to upload files to the ESP32 filesystem (SPIFFS) using AsyncElegantOTA.
Upload Files to Filesystem OTA (Over-the-Air) Updates – ESP32
In this section you’ll learn to upload files to the ESP32 filesystem (SPIFFS) using AsyncElegantOTA.
ESP32 Filesystem Upload Plugin
Before proceeding, you need to have the ESP32 Uploader Plugin installed in your Arduino IDE. Follow the next tutorial before proceeding:
- Install ESP32 Filesystem Uploader in Arduino IDE
Web Server with Files from SPIFFS
Imagine the scenario that you need to upload files to the ESP32 filesystem, for example: configuration files; HTML, CSS and JavaScript files to update the web server page; or any other file that you may want to save in SPIFFS via OTA.
To show you how to do this, we’ll create a new web server that serves files from SPIFFS: HTML, CSS and JavaScript files to build a web page that controls the ESP32 GPIOs remotely.
Before proceeding make sure you have the Arduino_JSON library by Arduino version 0.1.0 installed. You can install this library in the Arduino IDE Library Manager. Just go to Sketch > Include Library > Manage Libraries and search for the library name as follows: Arduino_JSON.

Copy the following code to your Arduino IDE.
/* Rui Santos Complete project details - Arduino IDE: https://RandomNerdTutorials.com/esp32-ota-over-the-air-arduino/ - VS Code: https://RandomNerdTutorials.com/esp32-ota-over-the-air-vs-code/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. */ // Import required libraries #include <Arduino.h> #include <WiFi.h> #include <AsyncTCP.h> #include <ESPAsyncWebServer.h> #include "SPIFFS.h" #include <Arduino_JSON.h> #include <AsyncElegantOTA.h> // Replace with your network credentials const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); // Create a WebSocket object AsyncWebSocket ws("/ws"); // Set number of outputs #define NUM_OUTPUTS 4 // Assign each GPIO to an output int outputGPIOs[NUM_OUTPUTS] = {2, 4, 12, 14}; // Initialize SPIFFS void initSPIFFS() { if (!SPIFFS.begin(true)) { Serial.println("An error has occurred while mounting SPIFFS"); } Serial.println("SPIFFS mounted successfully"); } // Initialize WiFi void initWiFi() { WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.print("Connecting to WiFi .."); while (WiFi.status() != WL_CONNECTED) { Serial.print('.'); delay(1000); } Serial.println(WiFi.localIP()); } String getOutputStates(){ JSONVar myArray; for (int i =0; i<NUM_OUTPUTS; i++){ myArray["gpios"][i]["output"] = String(outputGPIOs[i]); myArray["gpios"][i]["state"] = String(digitalRead(outputGPIOs[i])); } String jsonString = JSON.stringify(myArray); return jsonString; } void notifyClients(String state) { ws.textAll(state); } void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) { AwsFrameInfo *info = (AwsFrameInfo*)arg; if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { data[len] = 0; if (strcmp((char*)data, "states") == 0) { notifyClients(getOutputStates()); } else{ int gpio = atoi((char*)data); digitalWrite(gpio, !digitalRead(gpio)); notifyClients(getOutputStates()); } } } void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client,AwsEventType type, void *arg, uint8_t *data, size_t len) { switch (type) { case WS_EVT_CONNECT: Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); break; case WS_EVT_DISCONNECT: Serial.printf("WebSocket client #%u disconnected\n", client->id()); break; case WS_EVT_DATA: handleWebSocketMessage(arg, data, len); break; case WS_EVT_PONG: case WS_EVT_ERROR: break; } } void initWebSocket() { ws.onEvent(onEvent); server.addHandler(&ws); } void setup(){ // Serial port for debugging purposes Serial.begin(115200); // Set GPIOs as outputs for (int i =0; i<NUM_OUTPUTS; i++){ pinMode(outputGPIOs[i], OUTPUT); } initSPIFFS(); initWiFi(); initWebSocket(); // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/index.html", "text/html",false); }); server.serveStatic("/", SPIFFS, "/"); // Start ElegantOTA AsyncElegantOTA.begin(&server); // Start server server.begin(); } void loop() { ws.cleanupClients(); }View raw code
Insert your network credentials in the following variables and save the code.
const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD";Update Firmware
Create a .bin file from this sketch as shown previously (this sketch includes the needed lines of code to provide OTA capabilities).
Go to the ESP32 IP address followed by /update and upload the new firmware.
Next, we’ll see how to upload the files.
Update Filesystem
Under the project folder, create a folder called data and paste the following HTML, CSS, and JavaScript files (click on the links to download the files):
- HTML file: index.html
- CSS file: style.css
- JavaScript file: script.js
- Download all files
To find your project folder, you can simply go to Sketch > Show Sketch Folder.
This is where your data folder should be located and how it looks:

After this, with the ESP32 disconnected from your computer (that’s the whole purpose of OTA), click on ESP32 Data Sketch Upload.

You’ll get an error because there isn’t any ESP32 board connected to your computer – don’t worry.
Scroll up on the debugging window until you find the .spiffs.bin file location. That’s that file that you should upload (in our case the file is called Web_Server_OTA_ESP32_Example_2.spiffs.bin.

And this is the path where our file is located:
C:\Users\sarin\AppData\Local\Temp\arduino_build_675367\Web_server_OTA_ESP32_Example_2.spiffs.binTo access that file on my computer, I need to make hidden files visible (the AppData folder was not visible). Check if that’s also your case.

Once you reach the folder path, you want to get the file with .spiffs.bin extension.

To make things easier you can copy that file to your project folder.
Now that we have a .bin file from the data folder, we can upload that file. Go to your ESP32 IP address followed by /update. Make sure you have the Filesystem option selected.

Then, select the file with the .spiffs.bin extension.
After successfully uploading, click the Back button. And go to the root (/) URL again. You should get access to the following web page that controls the ESP32 outputs using Web Socket protocol.

To see the web server working, you can connect 4 LEDs to your ESP32 on GPIOS: 2, 4, 12, and 14. You should be able to control those outputs from the web server.
If you need to update something on your project, you just need to go to your ESP32 IP address followed by /update.
Congratulations! You’ve successfully uploaded files to the ESP32 filesystem using AsyncElegantOTA.
Wrapping Up
In this tutorial you’ve learned how to add OTA capabilities to your Async Web Servers using the AsyncElegantOTA library. This library is super simple to use and allows you to upload new firmware or files to SPIFFS effortlessly using a web page. In our opinion, the AsyncElegantOTA library is one of the best options to handle OTA web updates.
We hope you’ve found this tutorial useful.
Learn more about the ESP32 with our resources:
- Build ESP32 Web Servers with Arduino IDE (eBook)
- Learn ESP32 with Arduino IDE
- More ESP32 Projects and Tutorials…
Thanks for reading.
Tag » Arduino Ble Ota
-
ESP32 OTA Updates Over BLE From A React Web Application
-
Arduino BLE Sense 33 OTA Update - Installation & Troubleshooting
-
Fbiego/ESP32_BLE_OTA_Arduino: OTA Update On ESP32 Via BLE
-
ClaesClaes/Arduino-ESP32-BLE-OTA-iOS-SwiftUI - GitHub
-
ESP32 OTA Via BLE (Arduino) - YouTube
-
Arduino-esp32 Do OTA Via BLE - Stack Overflow
-
Performing OTA DFU Using Arduino Nano BLE Sense 33 (nRF52840)
-
ESP32 OTA With SwiftUI Over BLE Using NimBLE - IOS Example
-
OTA Update Your ESP32 Via BLE Without External Libraries - Part 1
-
[PDF] Over-The-Air (OTA) Device Firmware Upgrade (DFU) Guide
-
BLE Library For Esp32 Not Working With Android App
-
OTA With BLE - ESP32 Forum
-
Arduino IoT Cloud Gets Over-the-Air Update Support For MKR WiFi ...
-
Implement Ota Updates Over Ble On Esp32 By Fbiego - Fiverr