ESP32 OTA Updates over BLE from a React Web Application

Pages
Contributors: Englandsaurus
Favorited Favorite 2

Web App

This is my very first foray into Javascript and HTML, so I started with a React WebApp (follow this link to set up a vanilla one). You can download the final code to peruse as you read by clicking the button below. If you've set up all of your tools for React correctly, you should be able to navigate to /ESP32_OTA_BLE and run npm start to run the WebApp locally. It's also a pretty good idea to read up on this Google Developer Web Bluetooth tutorial and most importantly, make sure you know what Javascript Promises are and how they work.

You can poke around in the app, but let's go over the code in App.js to see what the App is actually doing.

App()

This is the function that is actually rendered by the DOM, so the basic structure of our page can go here. In this simple app, we put our connect button and user-prompt popup here. Our button, when clicked, launches our BTConnect function which begins searching for devices.

BTConnect()

The BTConnect function is called to search for and connect to our ESP32's BLE Server. Notice how we filter for services that match the myESP32 variable, which is declared in line 13 with a custom UUID. This UUID matches the one that the ESP32 uses for it's BLE Service, so when we look for devices, we'll only see the ESP32 that we've already programmed with our OTA sketch. Once we're connected, we save the BLE Service that we just connected to globally and run our CheckVersion() function.

onDisconnect()

onDisconnect is an event handler that will prompt the user if they want to reconnect to the device if it becomes disconnected. If the ESP32 is disconnected during an update, reset the ESP32 before trying again. This function is a little buggy and sometimes freezes so it needs some work.

CheckVersion()

CheckVersion() grabs the hardware and software version numbers from the ESP32 first and stores them globally. The App then grabs the JSON file from GitHub that has a list of our existing software versions and their compatible hardware versions. If the software versions don't match, we check to see if the newest version is compatible with our current hardware. If it is, we call PrompUserForUpdate() to ask if the user wants to update to a compatible version. If not, we check the next newest software version until we inevitably find some compatible software.

PromptUserForUpdate()

This function opens a simple pop-up with yes or no options. The pop-up informs the user of their current version and that it is out of date, and asks if they would like to update to the newest version compatible with their hardware. If they click yes, the App grabs the appropriate binary from GitHub, stores it, and calls SendFileOverBluetooth() passing the binary we just downloaded into the function.

SendFileOverBluetooth()

The first thing this function does is prepare the data to be sent by grabbing its initial size. This function sets up an event listener on the same GATT characteristic that we write our binary data to, so that when the ESP32 finishes handling the data, the ESP32 can write to the characteristic and trigger the event listener to send the next packet. Once we've set up the event listener to call SendBufferedData(), we call SendBufferedData() ourselves to kick off the Write/Flag/Write cycle.

SendBufferedData & RecursiveSend(characteristic, data)

SendBufferedData() takes our file and splits it up into the appropriate 512 byte size chunks (the size of a GATT characteristic) and calls RecursiveSend(characteristic, data) with the appropriate chunk. This function returns a promise to itself as it sends to ensure that we don't try and write to the characteristic while a GATT operation is still in progress.