Full Code of fbiego/ESP32_BLE_OTA_Arduino for AI

main 905466b49eca cached
23 files
60.0 KB
16.6k tokens
12 symbols
1 requests
Download .txt
Repository: fbiego/ESP32_BLE_OTA_Arduino
Branch: main
Commit: 905466b49eca
Files: 23
Total size: 60.0 KB

Directory structure:
gitextract_ain1bw9_/

├── LICENSE
├── README.md
├── esp32_ble_ota/
│   └── esp32_ble_ota.ino
├── esp32_ble_ota_lib_compact/
│   ├── .gitignore
│   ├── .vscode/
│   │   ├── extensions.json
│   │   └── settings.json
│   ├── README.md
│   ├── discover.py
│   ├── include/
│   │   └── README
│   ├── lib/
│   │   ├── README
│   │   └── ble_ota_dfu/
│   │       ├── keywords.txt
│   │       ├── library.json
│   │       ├── library.properties
│   │       └── src/
│   │           ├── ble_ota_dfu.cpp
│   │           ├── ble_ota_dfu.hpp
│   │           ├── freertos_utils.cpp
│   │           └── freertos_utils.hpp
│   ├── ota_updater.py
│   ├── platformio.ini
│   ├── src/
│   │   ├── main.cpp
│   │   └── main.hpp
│   └── test/
│       └── README
└── esp32_nim_ble_ota/
    └── esp32_nim_ble_ota.ino

================================================
FILE CONTENTS
================================================

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2021 Felix Biego

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# ESP32_BLE_OTA_Arduino
OTA update on ESP32 via BLE

- 1,038,544 bytes uploaded in 1min 25sec
- Speed: ~ `12kb/s peak`

[`esp32_ble_ota`](https://github.com/fbiego/ESP32_BLE_OTA_Arduino/tree/main/esp32_ble_ota) - 1,008,199 bytes

[`esp32_nim_ble_ota`](https://github.com/fbiego/ESP32_BLE_OTA_Arduino/tree/main/esp32_nim_ble_ota) - 563,051 bytes


## Android app

<a href='https://play.google.com/store/apps/details?id=com.fbiego.esp32.ota&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' height="100px" src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png'/></a>

## Python Script
Update from your computer

[`BLE_OTA_Python`](https://github.com/fbiego/BLE_OTA_Python)

## Video
[`DIY ESP32 clock with BLE OTA`](https://youtu.be/TU_O4UPm00A) - 12kb/s peak (optimized)

[`ESP32 OTA via BLE`](https://youtu.be/j4ELTS7QXFM) - 3kb/s (old)


================================================
FILE: esp32_ble_ota/esp32_ble_ota.ino
================================================
/*
   MIT License

   Copyright (c) 2021 Felix Biego

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.
*/


#include <Update.h>
#include "FS.h"
#include "FFat.h"
#include "SPIFFS.h"
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

#define BUILTINLED 2
#define FORMAT_SPIFFS_IF_FAILED true
#define FORMAT_FFAT_IF_FAILED true

#define USE_SPIFFS  //comment to use FFat

#ifdef USE_SPIFFS
#define FLASH SPIFFS
#define FASTMODE false    //SPIFFS write is slow
#else
#define FLASH FFat
#define FASTMODE true    //FFat is faster
#endif

#define NORMAL_MODE   0   // normal
#define UPDATE_MODE   1   // receiving firmware
#define OTA_MODE      2   // installing firmware

uint8_t updater[16384];
uint8_t updater2[16384];

#define SERVICE_UUID              "fb1e4001-54ae-4a28-9f74-dfccb248601d"
#define CHARACTERISTIC_UUID_RX    "fb1e4002-54ae-4a28-9f74-dfccb248601d"
#define CHARACTERISTIC_UUID_TX    "fb1e4003-54ae-4a28-9f74-dfccb248601d"

static BLECharacteristic* pCharacteristicTX;
static BLECharacteristic* pCharacteristicRX;

static bool deviceConnected = false, sendMode = false, sendSize = true;
static bool writeFile = false, request = false;
static int writeLen = 0, writeLen2 = 0;
static bool current = true;
static int parts = 0, next = 0, cur = 0, MTU = 0;
static int MODE = NORMAL_MODE;
unsigned long rParts, tParts;

static void rebootEspWithReason(String reason) {
  Serial.println(reason);
  delay(1000);
  ESP.restart();
}

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;

    }
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {

    //    void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code) {
    //      Serial.print("Status ");
    //      Serial.print(s);
    //      Serial.print(" on characteristic ");
    //      Serial.print(pCharacteristic->getUUID().toString().c_str());
    //      Serial.print(" with code ");
    //      Serial.println(code);
    //    }

    void onNotify(BLECharacteristic *pCharacteristic) {
      uint8_t* pData;
      std::string value = pCharacteristic->getValue();
      int len = value.length();
      pData = pCharacteristic->getData();
      if (pData != NULL) {
        //        Serial.print("Notify callback for characteristic ");
        //        Serial.print(pCharacteristic->getUUID().toString().c_str());
        //        Serial.print(" of data length ");
        //        Serial.println(len);
        Serial.print("TX  ");
        for (int i = 0; i < len; i++) {
          Serial.printf("%02X ", pData[i]);
        }
        Serial.println();
      }
    }

    void onWrite(BLECharacteristic *pCharacteristic) {
      uint8_t* pData;
      std::string value = pCharacteristic->getValue();
      int len = value.length();
      pData = pCharacteristic->getData();
      if (pData != NULL) {
        //        Serial.print("Write callback for characteristic ");
        //        Serial.print(pCharacteristic->getUUID().toString().c_str());
        //        Serial.print(" of data length ");
        //        Serial.println(len);
        //        Serial.print("RX  ");
        //        for (int i = 0; i < len; i++) {         // leave this commented
        //          Serial.printf("%02X ", pData[i]);
        //        }
        //        Serial.println();

        if (pData[0] == 0xFB) {
          int pos = pData[1];
          for (int x = 0; x < len - 2; x++) {
            if (current) {
              updater[(pos * MTU) + x] = pData[x + 2];
            } else {
              updater2[(pos * MTU) + x] = pData[x + 2];
            }
          }

        } else if  (pData[0] == 0xFC) {
          if (current) {
            writeLen = (pData[1] * 256) + pData[2];
          } else {
            writeLen2 = (pData[1] * 256) + pData[2];
          }
          current = !current;
          cur = (pData[3] * 256) + pData[4];
          writeFile = true;
          if (cur < parts - 1) {
            request = !FASTMODE;
          }
        } else if (pData[0] == 0xFD) {
          sendMode = true;
          if (FLASH.exists("/update.bin")) {
            FLASH.remove("/update.bin");
          }
        } else if (pData[0] == 0xFE) {
          rParts = 0;
          tParts = (pData[1] * 256 * 256 * 256) + (pData[2] * 256 * 256) + (pData[3] * 256) + pData[4];

          Serial.print("Available space: ");
          Serial.println(FLASH.totalBytes() - FLASH.usedBytes());
          Serial.print("File Size: ");
          Serial.println(tParts);

        } else if  (pData[0] == 0xFF) {
          parts = (pData[1] * 256) + pData[2];
          MTU = (pData[3] * 256) + pData[4];
          MODE = UPDATE_MODE;

        } else if (pData[0] == 0xEF) {
          FLASH.format();
          sendSize = true;
        }


      }

    }


};

static void writeBinary(fs::FS &fs, const char * path, uint8_t *dat, int len) {

  //Serial.printf("Write binary file %s\r\n", path);

  File file = fs.open(path, FILE_APPEND);

  if (!file) {
    Serial.println("- failed to open file for writing");
    return;
  }
  file.write(dat, len);
  file.close();
  writeFile = false;
  rParts += len;
}

void sendOtaResult(String result) {
  pCharacteristicTX->setValue(result.c_str());
  pCharacteristicTX->notify();
  delay(200);
}


void performUpdate(Stream &updateSource, size_t updateSize) {
  char s1 = 0x0F;
  String result = String(s1);
  if (Update.begin(updateSize)) {
    size_t written = Update.writeStream(updateSource);
    if (written == updateSize) {
      Serial.println("Written : " + String(written) + " successfully");
    }
    else {
      Serial.println("Written only : " + String(written) + "/" + String(updateSize) + ". Retry?");
    }
    result += "Written : " + String(written) + "/" + String(updateSize) + " [" + String((written / updateSize) * 100) + "%] \n";
    if (Update.end()) {
      Serial.println("OTA done!");
      result += "OTA Done: ";
      if (Update.isFinished()) {
        Serial.println("Update successfully completed. Rebooting...");
        result += "Success!\n";
      }
      else {
        Serial.println("Update not finished? Something went wrong!");
        result += "Failed!\n";
      }

    }
    else {
      Serial.println("Error Occurred. Error #: " + String(Update.getError()));
      result += "Error #: " + String(Update.getError());
    }
  }
  else
  {
    Serial.println("Not enough space to begin OTA");
    result += "Not enough space for OTA";
  }
  if (deviceConnected) {
    sendOtaResult(result);
    delay(5000);
  }
}

void updateFromFS(fs::FS &fs) {
  File updateBin = fs.open("/update.bin");
  if (updateBin) {
    if (updateBin.isDirectory()) {
      Serial.println("Error, update.bin is not a file");
      updateBin.close();
      return;
    }

    size_t updateSize = updateBin.size();

    if (updateSize > 0) {
      Serial.println("Trying to start update");
      performUpdate(updateBin, updateSize);
    }
    else {
      Serial.println("Error, file is empty");
    }

    updateBin.close();

    // when finished remove the binary from spiffs to indicate end of the process
    Serial.println("Removing update file");
    fs.remove("/update.bin");

    rebootEspWithReason("Rebooting to complete OTA update");
  }
  else {
    Serial.println("Could not load update.bin from spiffs root");
  }
}

void initBLE() {
  BLEDevice::init("ESP32 OTA");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristicTX = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY );
  pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
  pCharacteristicRX->setCallbacks(new MyCallbacks());
  pCharacteristicTX->setCallbacks(new MyCallbacks());
  pCharacteristicTX->addDescriptor(new BLE2902());
  pCharacteristicTX->setNotifyProperty(true);
  pService->start();


  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE OTA sketch");
  pinMode(BUILTINLED, OUTPUT);

#ifdef USE_SPIFFS
  if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
    Serial.println("SPIFFS Mount Failed");
    return;
  }
#else
  if (!FFat.begin()) {
    Serial.println("FFat Mount Failed");
    if (FORMAT_FFAT_IF_FAILED) FFat.format();
    return;
  }
#endif


  initBLE();

}

void loop() {

  switch (MODE) {

    case NORMAL_MODE:
      if (deviceConnected) {
        digitalWrite(BUILTINLED, HIGH);
        if (sendMode) {
          uint8_t fMode[] = {0xAA, FASTMODE};
          pCharacteristicTX->setValue(fMode, 2);
          pCharacteristicTX->notify();
          delay(50);
          sendMode = false;
        }

        if (sendSize) {
          unsigned long x = FLASH.totalBytes();
          unsigned long y = FLASH.usedBytes();
          uint8_t fSize[] = {0xEF, (uint8_t) (x >> 16), (uint8_t) (x >> 8), (uint8_t) x, (uint8_t) (y >> 16), (uint8_t) (y >> 8), (uint8_t) y};
          pCharacteristicTX->setValue(fSize, 7);
          pCharacteristicTX->notify();
          delay(50);
          sendSize = false;
        }

        // your loop code here
      } else {
        digitalWrite(BUILTINLED, LOW);
      }

      // or here

      break;

    case UPDATE_MODE:

      if (request) {
        uint8_t rq[] = {0xF1, (cur + 1) / 256, (cur + 1) % 256};
        pCharacteristicTX->setValue(rq, 3);
        pCharacteristicTX->notify();
        delay(50);
        request = false;
      }

      if (cur + 1 == parts) { // received complete file
        uint8_t com[] = {0xF2, (cur + 1) / 256, (cur + 1) % 256};
        pCharacteristicTX->setValue(com, 3);
        pCharacteristicTX->notify();
        delay(50);
        MODE = OTA_MODE;
      }

      if (writeFile) {
        if (!current) {
          writeBinary(FLASH, "/update.bin", updater, writeLen);
        } else {
          writeBinary(FLASH, "/update.bin", updater2, writeLen2);
        }
      }

      break;

    case OTA_MODE:

      if (writeFile) {
        if (!current) {
          writeBinary(FLASH, "/update.bin", updater, writeLen);
        } else {
          writeBinary(FLASH, "/update.bin", updater2, writeLen2);
        }
      }


      if (rParts == tParts) {
        Serial.println("Complete");
        delay(5000);
        updateFromFS(FLASH);
      } else {
        writeFile = true;
        Serial.println("Incomplete");
        Serial.print("Expected: ");
        Serial.print(tParts);
        Serial.print("Received: ");
        Serial.println(rParts);
        delay(2000);
      }
      break;

  }

}


================================================
FILE: esp32_ble_ota_lib_compact/.gitignore
================================================
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch


================================================
FILE: esp32_ble_ota_lib_compact/.vscode/extensions.json
================================================
{
    // See http://go.microsoft.com/fwlink/?LinkId=827846
    // for the documentation about the extensions.json format
    "recommendations": [
        "platformio.platformio-ide"
    ],
    "unwantedRecommendations": [
        "ms-vscode.cpptools-extension-pack"
    ]
}


================================================
FILE: esp32_ble_ota_lib_compact/.vscode/settings.json
================================================
{
    "cSpell.words": [
        "LOGD",
        "LOGI",
        "LOGW",
        "ledc",
        "LEDC",
    ]
}

================================================
FILE: esp32_ble_ota_lib_compact/README.md
================================================
# Compact version of the BLE OTA example

This directory contains a PlatformIO project which implement a compact version of the OTA. It also provides a library (in the lib folder) that allows to easily port BLE OTA to your own code.

**Note:** this version of the code is not compatible with the mobile app for the moment (the update mechanism is not exactly the same).

Furthermore, to use the FFAT mode you need to use another partition table (which you must configure in `platformio.ini`).


================================================
FILE: esp32_ble_ota_lib_compact/discover.py
================================================
import asyncio
from bleak import BleakScanner


async def run():
    for device in await BleakScanner.discover():
        print(f'{device.name} - {device.address}')

if __name__ == '__main__':
    try:
        asyncio.run(run())
    except KeyboardInterrupt:
        pass


================================================
FILE: esp32_ble_ota_lib_compact/include/README
================================================

This directory is intended for project header files.

A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.

```src/main.c

#include "header.h"

int main (void)
{
 ...
}
```

Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.

In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.

Read more about using header files in official GCC documentation:

* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes

https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html


================================================
FILE: esp32_ble_ota_lib_compact/lib/README
================================================

This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.

The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").

For example, see a structure of the following two libraries `Foo` and `Bar`:

|--lib
|  |
|  |--Bar
|  |  |--docs
|  |  |--examples
|  |  |--src
|  |     |- Bar.c
|  |     |- Bar.h
|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
|  |
|  |--Foo
|  |  |- Foo.c
|  |  |- Foo.h
|  |
|  |- README --> THIS FILE
|
|- platformio.ini
|--src
   |- main.c

and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>

int main (void)
{
  ...
}

```

PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.

More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html


================================================
FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/keywords.txt
================================================
# To be filled if you want to use it on Arduino    
#FUNCTIONS COLOR 			#D35400 - ORANGE			KEYWORD1
#FUNCTIONS COLOR			#D35400 - ORANGE			KEYWORD2
#STRUCTURE COLOR	 		#728E00 - GREEN				KEYWORD3
#VARIABLES COLOR 			#00979C - BLUE				LITERAL1


================================================
FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/library.json
================================================
{
  "name": "ble_ota_dfuU",
  "keywords": "BLE OTA DFU",
  "description": "BLE OTA DFU",
  "repository":
  {
    "type": "email",
    "url": "vincent.stragier@outlook.com"
  },
  "version": "1.0.0",
  "exclude": "doc",
  "frameworks": "arduino",
  "platforms": ["esp32"]
}


================================================
FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/library.properties
================================================
name=ble_ota_dfu
version=1.0.0
author=Vincent STRAGIER
maintainer=Vincent STRAGIER
sentence=BLE OTA DFU
paragraph=BLE OTA DFU
category=Other
url=mailto:vincent.stragier@outlook.com
architectures=esp32

================================================
FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/ble_ota_dfu.cpp
================================================
/* Copyright 2022 Vincent Stragier */
#include "ble_ota_dfu.hpp"

QueueHandle_t start_update_queue;
QueueHandle_t update_uploading_queue;

void task_install_update(void *parameters) {
  FS file_system = FLASH;
  const char path[] = "/update.bin";
  uint8_t data = 0;
  BLE_OTA_DFU *OTA_DFU_BLE;
  OTA_DFU_BLE = reinterpret_cast<BLE_OTA_DFU *>(parameters);
  delay(100);

  // Wait for the upload to be completed
  bool start_update = false;
  xQueuePeek(start_update_queue, &start_update, portMAX_DELAY);
  while (!start_update) {
    delay(500);
    xQueuePeek(start_update_queue, &start_update, portMAX_DELAY);
  }

  ESP_LOGE(TAG, "Starting OTA update");

  // Open update.bin file.
  File update_binary = FLASH.open(path);

  // If the file cannot be loaded, return.
  if (!update_binary) {
    ESP_LOGE(TAG, "Could not load update.bin from spiffs root");
    vTaskDelete(NULL);
  }

  // Verify that the file is not a directory
  if (update_binary.isDirectory()) {
    ESP_LOGE(TAG, "Error, update.bin is not a file");
    update_binary.close();
    vTaskDelete(NULL);
  }

  // Get binary file size
  size_t update_size = update_binary.size();

  // Proceed to the update if the file is not empty
  if (update_size <= 0) {
    ESP_LOGE(TAG, "Error, update file is empty");
    update_binary.close();
    vTaskDelete(NULL);
  }

  ESP_LOGI(TAG, "Starting the update");
  // perform_update(update_binary, update_size);
  String result = (String) static_cast<char>(0x0F);

  // Init update
  if (Update.begin(update_size)) {
    // Perform the update
    size_t written = Update.writeStream(update_binary);

    ESP_LOGI(TAG, "Written: %d/%d. %s", written, update_size,
             written == update_size ? "Success!" : "Retry?");
    result += "Written : " + String(written) + "/" + String(update_size) +
              " [" + String((written / update_size) * 100) + " %] \n";

    // Check update
    if (Update.end()) {
      ESP_LOGI(TAG, "OTA done!");
      result += "OTA Done: ";

      if (Update.isFinished()) {
        ESP_LOGI(TAG, "Update successfully completed. Rebooting...");
      } else {
        ESP_LOGE(TAG, "Update not finished? Something went wrong!");
      }

      result += Update.isFinished() ? "Success!\n" : "Failed!\n";
    } else {
      ESP_LOGE(TAG, "Error Occurred. Error #: %d", Update.getError());
      result += "Error #: " + String(Update.getError());
    }
  } else {
    ESP_LOGE(TAG, "Not enough space to begin BLE OTA DFU");
    result += "Not enough space to begin BLE OTA DFU";
  }

  update_binary.close();

  // When finished remove the binary from spiffs
  // to indicate the end of the process
  ESP_LOGI(TAG, "Removing update file");
  FLASH.remove(path);

  if (OTA_DFU_BLE->connected()) {
    // Return the result to the client (tells the client if the update was a
    // successfull or not)
    ESP_LOGI(TAG, "Sending result to client");
    OTA_DFU_BLE->send_OTA_DFU(result);
    // OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->setValue(result);
    // OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->notify();
    ESP_LOGE(TAG, "%s", result.c_str());
    ESP_LOGI(TAG, "Result sent to client");
    delay(5000);
  }

  ESP_LOGE(TAG, "Rebooting ESP32: complete OTA update");
  delay(5000);
  ESP.restart();

  // ESP_LOGI(TAG, "Installation is complete");
  vTaskDelete(NULL);
}

//    void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t
//    code) {
//      Serial.print("Status ");
//      Serial.print(s);
//      Serial.print(" on characteristic ");
//      Serial.print(pCharacteristic->getUUID().toString().c_str());
//      Serial.print(" with code ");
//      Serial.println(code);
//    }

uint16_t BLEOverTheAirDeviceFirmwareUpdate::write_binary(fs::FS *file_system,
                                                         const char *path,
                                                         uint8_t *data,
                                                         uint16_t length,
                                                         bool keep_open) {
  static File file;

  // Append data to the file

  if (!file_open) {
    ESP_LOGI(TAG, "Opening binary file %s\r\n", path);
    file = file_system->open(path, FILE_WRITE);
    file_open = true;
  }

  if (!file) {
    ESP_LOGE(TAG, "Failed to open the file to write");
    return 0;
  }

  if (data != nullptr) {
    ESP_LOGI(TAG, "Write binary file %s\r\n", path);
    file.write(data, length);
  }

  if (keep_open) {
    return length;
  } else {
    file.close();
    file_open = false;
    return 0;
  }
}

void BLEOverTheAirDeviceFirmwareUpdate::onNotify(
    BLECharacteristic *pCharacteristic) {
#ifdef DEBUG_BLE_OTA_DFU_TX
  // uint8_t *pData;
  std::string value = pCharacteristic->getValue();
  uint16_t len = value.length();
  // pData = pCharacteristic->getData();
  uint8_t *pData = (uint8_t *)value.data();

  if (pData != NULL) {
    ESP_LOGD(TAG, "Notify callback for characteristic %s  of data length %d",
             pCharacteristic->getUUID().toString().c_str(), len);

    // Print transferred packets
    Serial.print("TX  ");
    for (uint16_t i = 0; i < len; i++) {
      Serial.printf("%02X ", pData[i]);
    }
    Serial.println();
  }
#endif
}

void BLEOverTheAirDeviceFirmwareUpdate::onWrite(
    BLECharacteristic *pCharacteristic) {
  // uint8_t *pData;
  std::string value = pCharacteristic->getValue();
  uint16_t len = value.length();
  // pData = pCharacteristic->getData();
  uint8_t *pData = (uint8_t *)value.data();

  // Check that data have been received
  if (pData != NULL) {
// #define DEBUG_BLE_OTA_DFU_RX
#ifdef DEBUG_BLE_OTA_DFU_RX
    ESP_LOGD(TAG, "Write callback for characteristic %s of data length %d",
             pCharacteristic->getUUID().toString().c_str(), len);
    Serial.print("RX  ");
    for (uint16_t index = 0; index < len; index++) {
      Serial.printf("%02X ", pData[i]);
    }
    Serial.println();
#endif
    switch (pData[0]) {
      // Send total and used sizes
    case 0xEF: {
      FLASH.format();

      // Send flash size
      uint16_t total_size = FLASH.totalBytes();
      uint16_t used_size = FLASH.usedBytes();
      uint8_t flash_size[] = {0xEF,
                              static_cast<uint8_t>(total_size >> 16),
                              static_cast<uint8_t>(total_size >> 8),
                              static_cast<uint8_t>(total_size),
                              static_cast<uint8_t>(used_size >> 16),
                              static_cast<uint8_t>(used_size >> 8),
                              static_cast<uint8_t>(used_size)};
      OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->setValue(flash_size, 7);
      OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->notify();
      delay(10);
    } break;

      // Write parts to RAM
    case 0xFB: {
      // pData[1] is the position of the next part
      for (uint16_t index = 0; index < len - 2; index++) {
        updater[!selected_updater][(pData[1] * MTU) + index] = pData[index + 2];
      }
    } break;

      // Write updater content to the flash
    case 0xFC: {
      selected_updater = !selected_updater;
      write_len[selected_updater] = (pData[1] * 256) + pData[2];
      current_progression = (pData[3] * 256) + pData[4];

      received_file_size +=
          write_binary(&FLASH, "/update.bin", updater[selected_updater],
                       write_len[selected_updater]);

      if ((current_progression < parts - 1) && !FASTMODE) {
        uint8_t progression[] = {0xF1,
                                 (uint8_t)((current_progression + 1) / 256),
                                 (uint8_t)((current_progression + 1) % 256)};
        OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->setValue(progression, 3);
        OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->notify();
        delay(10);
      }

      ESP_LOGI(TAG, "Upload progress: %d/%d", current_progression + 1, parts);
      if (current_progression + 1 == parts) {
        // If all the file has been received, send the progression
        uint8_t progression[] = {0xF2,
                                 (uint8_t)((current_progression + 1) / 256),
                                 (uint8_t)((current_progression + 1) % 256)};
        OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->setValue(progression, 3);
        OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->notify();
        delay(10);

        if (received_file_size != expected_file_size) {
          // received_file_size += (pData[1] * 256) + pData[2];
          received_file_size +=
              write_binary(&FLASH, "/update.bin", updater[selected_updater],
                           write_len[selected_updater]);

          if (received_file_size > expected_file_size) {
            ESP_LOGW(TAG, "Unexpected size:\n Expected: %d\nReceived: %d",
                     expected_file_size, received_file_size);
          }

        } else {
          ESP_LOGI(TAG, "Installing update");

          // Start the installation
          write_binary(&FLASH, "/update.bin", nullptr, 0, false);
          bool start_update = true;
          xQueueOverwrite(start_update_queue, &start_update);
        }
      }
    } break;

      // Remove previous file and send transfer mode
    case 0xFD: {
      // Remove previous (failed?) update
      if (FLASH.exists("/update.bin")) {
        ESP_LOGI(TAG, "Removing previous update");
        FLASH.remove("/update.bin");
      }

      // Send mode ("fast" or "slow")
      uint8_t mode[] = {0xAA, FASTMODE};
      OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->setValue(mode, 2);
      OTA_DFU_BLE->pCharacteristic_BLE_OTA_DFU_TX->notify();
      delay(10);
    } break;

      // Keep track of the received file and of the expected file sizes
    case 0xFE:
      received_file_size = 0;
      expected_file_size = (pData[1] * 16777216) + (pData[2] * 65536) +
                           (pData[3] * 256) + pData[4];

      ESP_LOGI(TAG, "Available space: %d\nFile Size: %d\n",
               FLASH.totalBytes() - FLASH.usedBytes(), expected_file_size);
      break;

      // Switch to update mode
    case 0xFF:
      parts = (pData[1] * 256) + pData[2];
      MTU = (pData[3] * 256) + pData[4];
      break;

    default:
      ESP_LOGW(TAG, "Unknown command: %02X", pData[0]);
      break;
    }
    // ESP_LOGE(TAG, "Not stuck in loop");
  }
  delay(1);
}

bool BLE_OTA_DFU::configure_OTA(NimBLEServer *pServer) {
  // Init FLASH
#ifdef USE_SPIFFS
  if (!SPIFFS.begin(FORMAT_FLASH_IF_MOUNT_FAILED)) {
    ESP_LOGE(TAG, "SPIFFS Mount Failed");
    return false;
  }
  ESP_LOGI(TAG, "SPIFFS Mounted");
#else
  if (!FFat.begin()) {
    ESP_LOGE(TAG, "FFat Mount Failed");
    if (FORMAT_FLASH_IF_MOUNT_FAILED)
      FFat.format();
    return false;
  }
  ESP_LOGI(TAG, "FFat Mounted");
#endif

  // Get the pointer to the pServer
  this->pServer = pServer;
  // Create the BLE OTA DFU Service
  pServiceOTA = pServer->createService(SERVICE_OTA_BLE_UUID);

  if (pServiceOTA == nullptr) {
    return false;
  }

  BLECharacteristic *pCharacteristic_BLE_OTA_DFU_RX =
      pServiceOTA->createCharacteristic(CHARACTERISTIC_OTA_BL_UUID_RX,
                                        NIMBLE_PROPERTY::WRITE |
                                            NIMBLE_PROPERTY::WRITE_NR);

  if (pCharacteristic_BLE_OTA_DFU_RX == nullptr) {
    return false;
  }

  auto *bleOTACharacteristicCallbacksRX =
      new BLEOverTheAirDeviceFirmwareUpdate();
  bleOTACharacteristicCallbacksRX->OTA_DFU_BLE = this;
  pCharacteristic_BLE_OTA_DFU_RX->setCallbacks(bleOTACharacteristicCallbacksRX);

  pCharacteristic_BLE_OTA_DFU_TX = pServiceOTA->createCharacteristic(
      CHARACTERISTIC_OTA_BL_UUID_TX, NIMBLE_PROPERTY::NOTIFY);

  if (pCharacteristic_BLE_OTA_DFU_TX == nullptr) {
    return false;
  }

  // Start the BLE UART service
  pServiceOTA->start();
  return true;
}

void BLE_OTA_DFU::start_OTA() {
  bool state = false;
  initialize_queue(&start_update_queue, bool, &state, 1);
  initialize_queue(&update_uploading_queue, bool, &state, 1);
  // initialize_empty_queue(&update_queue, uint8_t, UPDATE_QUEUE_SIZE);

  ESP_LOGI(TAG, "Available heap memory: %d", ESP.getFreeHeap());
  // ESP_LOGE(TAG, "Available stack memory: %d",

  ESP_LOGI(TAG, "Available free space: %d",
           FLASH.totalBytes() - FLASH.usedBytes());
  // ESP_LOGE(TAG, "Available free blocks: %d", FLASH.blockCount());
  TaskHandle_t taskInstallUpdate = NULL;

  xTaskCreatePinnedToCoreAndAssert(task_install_update, "task_install_update",
                                   5120, static_cast<void *>(this), 5,
                                   &taskInstallUpdate, 1);

  ESP_LOGI(TAG, "Available memory (after task started): %d", ESP.getFreeHeap());
}

bool BLE_OTA_DFU::begin(String local_name) {
  // Create the BLE Device
  BLEDevice::init(local_name.c_str());

  ESP_LOGI(TAG, "Starting BLE UART services");

  // Create the BLE Server
  pServer = BLEDevice::createServer();

  if (pServer == nullptr) {
    return false;
  }

  this->configure_OTA(pServer);

  // Start advertising
  pServer->getAdvertising()->addServiceUUID(pServiceOTA->getUUID());
  pServer->getAdvertising()->start();

  this->start_OTA();
  return true;
}

bool BLE_OTA_DFU::connected() {
  // True if connected
  return pServer->getConnectedCount() > 0;
}

void BLE_OTA_DFU::send_OTA_DFU(uint8_t value) {
  uint8_t _value = value;
  this->pCharacteristic_BLE_OTA_DFU_TX->setValue(&_value, 1);
  this->pCharacteristic_BLE_OTA_DFU_TX->notify();
}

void BLE_OTA_DFU::send_OTA_DFU(uint8_t *value, size_t size) {
  this->pCharacteristic_BLE_OTA_DFU_TX->setValue(value, size);
  this->pCharacteristic_BLE_OTA_DFU_TX->notify();
}

void BLE_OTA_DFU::send_OTA_DFU(String value) {
  this->pCharacteristic_BLE_OTA_DFU_TX->setValue(value.c_str());
  this->pCharacteristic_BLE_OTA_DFU_TX->notify();
}


================================================
FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/ble_ota_dfu.hpp
================================================
/* Copyright 2022 Vincent Stragier */
// Highly inspired by https://github.com/fbiego/ESP32_BLE_OTA_Arduino
#pragma once
#ifndef SRC_BLE_OTA_DFU_HPP_
#define SRC_BLE_OTA_DFU_HPP_

#include "./freertos_utils.hpp"
#include <Arduino.h>
#include <FS.h>
#include <NimBLEDevice.h>
#include <Update.h>
#include <string>

// comment to use FFat
#define USE_SPIFFS

#ifdef USE_SPIFFS
// SPIFFS write is slower
#include <SPIFFS.h>
#define FLASH SPIFFS
const bool FASTMODE = false;
#else
// FFat is faster
#include <FFat.h>
#define FLASH FFat
const bool FASTMODE = true;
#endif
// #endif

const char SERVICE_OTA_BLE_UUID[] = "fe590001-54ae-4a28-9f74-dfccb248601d";
const char CHARACTERISTIC_OTA_BL_UUID_RX[] =
    "fe590002-54ae-4a28-9f74-dfccb248601d";
const char CHARACTERISTIC_OTA_BL_UUID_TX[] =
    "fe590003-54ae-4a28-9f74-dfccb248601d";

const bool FORMAT_FLASH_IF_MOUNT_FAILED = true;
const uint32_t UPDATER_SIZE = 20000;

/* Dummy class */
class BLE_OTA_DFU;

class BLEOverTheAirDeviceFirmwareUpdate : public BLECharacteristicCallbacks {
private:
  bool selected_updater = true;
  bool file_open = false;
  uint8_t updater[2][UPDATER_SIZE];
  uint16_t write_len[2] = {0, 0};
  uint16_t parts = 0, MTU = 0;
  uint16_t current_progression = 0;
  uint32_t received_file_size, expected_file_size;

public:
  friend class BLE_OTA_DFU;
  BLE_OTA_DFU *OTA_DFU_BLE;

  uint16_t write_binary(fs::FS *file_system, const char *path, uint8_t *data,
                        uint16_t length, bool keep_open = true);
  void onNotify(BLECharacteristic *pCharacteristic);
  void onWrite(BLECharacteristic *pCharacteristic);
};

class BLE_OTA_DFU {
private:
  BLEServer *pServer = nullptr;
  BLEService *pServiceOTA = nullptr;
  BLECharacteristic *pCharacteristic_BLE_OTA_DFU_TX = nullptr;
  friend class BLEOverTheAirDeviceFirmwareUpdate;

public:
  BLE_OTA_DFU() = default;
  ~BLE_OTA_DFU() = default;

  bool configure_OTA(NimBLEServer *pServer);
  void start_OTA();

  bool begin(String local_name);

  bool connected();

  void send_OTA_DFU(uint8_t value);
  void send_OTA_DFU(uint8_t *value, size_t size);
  void send_OTA_DFU(String value);

  friend void task_install_update(void *parameters);
};

#endif /* SRC_BLE_OTA_DFU_HPP_ */


================================================
FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/freertos_utils.cpp
================================================
/* Copyright 2022 Vincent Stragier */
#include "freertos_utils.hpp"

BaseType_t xTaskCreatePinnedToCoreAndAssert(
    TaskFunction_t pvTaskCode, const char *pcName, uint32_t usStackDepth,
    void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pvCreatedTask,
    BaseType_t xCoreID) {

  BaseType_t xReturn =
      xTaskCreatePinnedToCore(pvTaskCode, pcName, usStackDepth, pvParameters,
                              uxPriority, pvCreatedTask, xCoreID);

  configASSERT(pvCreatedTask);

  return xReturn;
}


================================================
FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/freertos_utils.hpp
================================================
/* Copyright 2022 Vincent Stragier */
#pragma once
#ifndef SRC_FREERTOS_UTILS_HPP_
#define SRC_FREERTOS_UTILS_HPP_

#include <Arduino.h>

// Initialize the queue
#define initialize_queue(queue, T, initial_value, size)                        \
  _initialize_queue<T>((queue), (#queue), (size), (initial_value))
#define initialize_empty_queue(queue, T, size)                                 \
  _initialize_queue<T>((queue), (#queue), (size))

template <typename T>
void _initialize_queue(QueueHandle_t *queue, const char *queue_name,
                       size_t size, T *initial_value = nullptr) {
  *queue = xQueueCreate(size, sizeof(T));

  ESP_LOGI(TAG, "Creating the queue \"%s\"", queue_name);
  // Init start update queue
  if (*queue == NULL || *queue == nullptr) {
    ESP_LOGE(TAG, "Error creating the queue \"%s\"", queue_name);
  }

  if (initial_value == nullptr || initial_value == NULL) {
    return;
  }

  if (!xQueueSend(*queue, initial_value, portMAX_DELAY)) {
    ESP_LOGE(TAG, "Error initializing the queue \"%s\"", queue_name);
  }
}

// Create a task and assert it's creation
BaseType_t xTaskCreatePinnedToCoreAndAssert(
    TaskFunction_t pvTaskCode, const char *pcName, uint32_t usStackDepth,
    void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pvCreatedTask,
    BaseType_t xCoreID);

#endif /* SRC_FREERTOS_UTILS_HPP_ */


================================================
FILE: esp32_ble_ota_lib_compact/ota_updater.py
================================================
from __future__ import print_function
import os
import asyncio
import sys
import re
from time import sleep

from bleak import BleakClient, BleakScanner
# from bleak.exc import BleakError

header = """#####################################################################
    ------------------------BLE OTA update---------------------
    Arduino code @ https://github.com/fbiego/ESP32_BLE_OTA_Arduino
#####################################################################"""

UART_SERVICE_UUID = "fe590001-54ae-4a28-9f74-dfccb248601d"
UART_RX_CHAR_UUID = "fe590002-54ae-4a28-9f74-dfccb248601d"
UART_TX_CHAR_UUID = "fe590003-54ae-4a28-9f74-dfccb248601d"

PART = 19000
MTU = 250

ble_ota_dfu_end = False


async def start_ota(ble_address: str, filename: str):
    device = await BleakScanner.find_device_by_address(ble_address, timeout=20.0)
    disconnected_event = asyncio.Event()
    total = 0
    file_content = None
    client = None

    def handle_disconnect(_: BleakClient):
        print("Device disconnected !")
        disconnected_event.set()
        sleep(1)
        # sys.exit(0)

    async def handle_rx(_: int, data: bytearray):
        # print(f'\nReceived: {data = }\n')
        match data[0]:
            case 0xAA:
                print("Starting transfer, mode:", data[1])
                print_progress_bar(0, total, prefix='Upload progress:',
                                   suffix='Complete', length=50)

                match data[1]:
                    case 0:  # Slow mode
                        # Send first part
                        await send_part(0, file_content, client)
                    case 1:  # Fast mode
                        for index in range(file_parts):
                            await send_part(index, file_content, client)
                            print_progress_bar(index + 1, total,
                                               prefix='Upload progress:',
                                               suffix='Complete', length=50)

            case 0xF1:  # Send next part and update progress bar
                next_part_to_send = int.from_bytes(
                    data[2:3], byteorder='little')
                # print("Next part:", next_part_to_send, "\n")
                await send_part(next_part_to_send, file_content, client)
                print_progress_bar(next_part_to_send + 1, total,
                                   prefix='Upload progress:',
                                   suffix='Complete', length=50)

            case 0xF2:  # Install firmware
                # ins = 'Installing firmware'
                # print("Installing firmware")
                pass

            case 0x0F:
                print("OTA result: ", str(data[1:], 'utf-8'))
                global ble_ota_dfu_end
                ble_ota_dfu_end = True

    def print_progress_bar(iteration: int, total: int, prefix: str = '', suffix: str = '', decimals: int = 1, length: int = 100, filler: str = '█', print_end: str = "\r"):
        """
        Call in a loop to create terminal progress bar
        @params:
            iteration   - Required  : current iteration (Int)
            total       - Required  : total iterations (Int)
            prefix      - Optional  : prefix string (Str)
            suffix      - Optional  : suffix string (Str)
            decimals    - Optional  : positive number of decimals in percent complete (Int)
            length      - Optional  : character length of bar (Int)
            filler      - Optional  : bar fill character (Str)
            print_end   - Optional  : end character (e.g. "\r", "\r\n") (Str)
        """
        percent = ("{0:." + str(decimals) + "f}").format(100 *
                                                         (iteration / float(total)))
        filled_length = (length * iteration) // total
        bar = filler * filled_length + '-' * (length - filled_length)
        print(f'\r{prefix} |{bar}| {percent} % {suffix}', end=print_end)
        # Print new line upon complete
        if iteration == total:
            print()

    async def send_part(position: int, data: bytearray, client: BleakClient):
        start = position * PART
        end = (position + 1) * PART
        # print(locals())
        if len(data) < end:
            end = len(data)

        data_length = end - start
        parts = data_length // MTU
        for part_index in range(parts):
            to_be_sent = bytearray([0xFB, part_index])
            for mtu_index in range(MTU):
                to_be_sent.append(
                    data[(position*PART)+(MTU * part_index) + mtu_index])
            await send_data(client, to_be_sent)

        if data_length % MTU:
            remaining = data_length % MTU
            to_be_sent = bytearray([0xFB, parts])
            for index in range(remaining):
                to_be_sent.append(
                    data[(position*PART)+(MTU * parts) + index])
            await send_data(client, to_be_sent)

        await send_data(client, bytearray([0xFC, data_length//256, data_length %
                                           256, position//256, position % 256]), True)

    async def send_data(client: BleakClient, data: bytearray, response: bool = False):
        # print(f'{locals()["data"]}')
        await client.write_gatt_char(UART_RX_CHAR_UUID, data, response)

    if not device:
        print("-----------Failed--------------")
        print(f"Device with address {ble_address} could not be found.")
        return
        #raise BleakError(f"A device with address {ble_address} could not be found.")

    async with BleakClient(device, disconnected_callback=handle_disconnect) as local_client:
        client = local_client

        # Load file
        print("Reading from: ", filename)
        file_content = open(filename, "rb").read()
        file_parts = -(len(file_content) // -PART)
        total = file_parts
        file_length = len(file_content)
        print(f'File size: {len(file_content)}')

        # Set the UUID of the service you want to connect to and the callback
        await client.start_notify(UART_TX_CHAR_UUID, handle_rx)
        await asyncio.sleep(1.0)

        # Send file length
        await send_data(client, bytearray([0xFE,
                                           file_length >> 24 & 0xFF,
                                           file_length >> 16 & 0xFF,
                                           file_length >> 8 & 0xFF,
                                           file_length & 0xFF]))

        # Send number of parts and MTU value
        await send_data(client, bytearray([0xFF,
                                           file_parts//256,
                                           file_parts % 256,
                                           MTU // 256,
                                           MTU % 256]))

        # Remove previous update and receive transfer mode (start the update)
        await send_data(client, bytearray([0xFD]))

        # Wait til the update is complete
        while not ble_ota_dfu_end:
            await asyncio.sleep(1.0)

        print("Waiting for disconnect... ", end="")

        await disconnected_event.wait()
        print("-----------Complete--------------")


def is_valid_address(value: str = None) -> bool:
    # Regex to check valid MAC address
    regex_0 = (r"^([0-9A-Fa-f]{2}[:-])"
               r"{5}([0-9A-Fa-f]{2})|"
               r"([0-9a-fA-F]{4}\\."
               r"[0-9a-fA-F]{4}\\."
               r"[0-9a-fA-F]{4}){17}$")
    regex_1 = (r"^[{]?[0-9a-fA-F]{8}"
               r"-([0-9a-fA-F]{4}-)"
               r"{3}[0-9a-fA-F]{12}[}]?$")

    # Compile the ReGex
    regex_0 = re.compile(regex_0)
    regex_1 = re.compile(regex_1)

    # If the string is empty return false
    if value is None:
        return False

    # Return if the string matched the ReGex
    if re.search(regex_0, value) and len(value) == 17:
        return True

    return re.search(regex_1, value) and len(value) == 36


if __name__ == "__main__":
    print(header)
    # Check if the user has entered enough arguments
    # sys.argv.append("C8:C9:A3:D2:60:8E")
    # sys.argv.append("firmware.bin")

    if len(sys.argv) < 3:
        print("Specify the device address and firmware file")
        import sys
        import os
        filename = os.path.join(os.path.dirname(
            __file__), '.pio', 'build', 'esp32doit-devkit-v1', 'firmware.bin')
        filename = filename if os.path.exists(filename) else "firmware.bin"
        print(
            f"$ {sys.executable} \"{__file__}\" \"C8:C9:A3:D2:60:8E\" \"{filename}\"")
        exit(1)

    print("Trying to start OTA update")
    ble_address = sys.argv[1]
    filename = sys.argv[2]

    # Check if the address is valid
    if not is_valid_address(ble_address):
        print(f"Invalid Address: {ble_address}")
        exit(2)

    # Check if the file exists
    if not os.path.exists(filename):
        print(f"File not found: {filename}")
        exit(3)

    try:
        # Start the OTA update
        asyncio.run(start_ota(ble_address, filename))
    except KeyboardInterrupt:
        print("\nExiting...")
        exit(0)
    except OSError:
        print("\nExiting (OSError)...")
        exit(1)
    except Exception:
        import traceback
        traceback.print_exc()
        exit(2)


================================================
FILE: esp32_ble_ota_lib_compact/platformio.ini
================================================
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32dev
framework = arduino
; ESP_LOGE - error (lowest) = 1
; ESP_LOGW - warning = 2
; ESP_LOGI - info = 3
; ESP_LOGD - debug = 4
; ESP_LOGV - verbose (highest) = 5
; build_flags = -DCORE_DEBUG_LEVEL=3
; build_type = debug

; board_build.partitions = default_ffat.csv
board_build.partitions = default.csv

; Serial Monitor options
; https://docs.platformio.org/en/latest/core/userguide/device/cmd_monitor.html
monitor_speed = 115200
monitor_rts = 0
monitor_dtr = 0

monitor_filters =
  ; time
  ; send_on_enter
  esp32_exception_decoder
  ; hexlify
  ; colorize

; Libraries
lib_deps =
  https://github.com/h2zero/NimBLE-Arduino.git

; Run before compilation
; extra_scripts =
;   pre:some_script.py

; Configure checking tool
;, pvs-studio,  
check_tool = cppcheck, clangtidy
check_flags =
  cppcheck: --addon=cert.py
check_skip_packages = yes


================================================
FILE: esp32_ble_ota_lib_compact/src/main.cpp
================================================
/* Copyright 2022 Vincent Stragier */
#include "main.hpp"

///////////////////
///    Setup    ///
///////////////////
void setup() { ota_dfu_ble.begin("Test OTA DFU"); }

//////////////////
///    Loop    ///
//////////////////
void loop() {
  // Kill the holly loop()
  // Delete the task, comment if you want to keep the loop()
  vTaskDelete(NULL);
}

///////////////////////
///    Functions    ///
///////////////////////


================================================
FILE: esp32_ble_ota_lib_compact/src/main.hpp
================================================
/* Copyright 2022 Vincent Stragier */

#ifndef SRC_MAIN_HPP_
#define SRC_MAIN_HPP_
///////////////////////
///    Libraries    ///
///////////////////////

#include <Arduino.h>
#include <ble_ota_dfu.hpp>

///////////////////////
///    Variables    ///
///////////////////////
BLE_OTA_DFU ota_dfu_ble;

#endif /* SRC_MAIN_HPP_ */


================================================
FILE: esp32_ble_ota_lib_compact/test/README
================================================

This directory is intended for PlatformIO Unit Testing and project tests.

Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.

More information about PlatformIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html


================================================
FILE: esp32_nim_ble_ota/esp32_nim_ble_ota.ino
================================================
/*
   MIT License
   Copyright (c) 2021 Felix Biego
   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
   in the Software without restriction, including without limitation the rights
   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:
   The above copyright notice and this permission notice shall be included in all
   copies or substantial portions of the Software.
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   SOFTWARE.
*/

#include <Update.h>
#include "FS.h"
#include "FFat.h"
#include "SPIFFS.h"
#include <NimBLEDevice.h>
//#include <SD.h>             // For OTA with SD Card

#define BUILTINLED 2
#define FORMAT_SPIFFS_IF_FAILED true
#define FORMAT_FFAT_IF_FAILED true

#define USE_SPIFFS  //comment to use FFat

#ifdef USE_SPIFFS
#define FLASH SPIFFS
#define FASTMODE false    //SPIFFS write is slow
#else
#define FLASH FFat
#define FASTMODE true    //FFat is faster
#endif

#define NORMAL_MODE   0   // normal
#define UPDATE_MODE   1   // receiving firmware
#define OTA_MODE      2   // installing firmware

uint8_t updater[16384];
uint8_t updater2[16384];

#define SERVICE_UUID              "fb1e4001-54ae-4a28-9f74-dfccb248601d"
#define CHARACTERISTIC_UUID_RX    "fb1e4002-54ae-4a28-9f74-dfccb248601d"
#define CHARACTERISTIC_UUID_TX    "fb1e4003-54ae-4a28-9f74-dfccb248601d"

static BLECharacteristic* pCharacteristicTX;
static BLECharacteristic* pCharacteristicRX;

static bool deviceConnected = false, sendMode = false, sendSize = true;
static bool writeFile = false, request = false;
static int writeLen = 0, writeLen2 = 0;
static bool current = true;
static int parts = 0, next = 0, cur = 0, MTU = 0;
static int MODE = NORMAL_MODE;
unsigned long rParts, tParts;

static void rebootEspWithReason(String reason) {
  Serial.println(reason);
  delay(1000);
  ESP.restart();
}

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("Connected");
      deviceConnected = true;

    }
    void onDisconnect(BLEServer* pServer) {
      Serial.println("disconnected");
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {

    //    void onStatus(BLECharacteristic* pCharacteristic, Status s, uint32_t code) {
    //      Serial.print("Status ");
    //      Serial.print(s);
    //      Serial.print(" on characteristic ");
    //      Serial.print(pCharacteristic->getUUID().toString().c_str());
    //      Serial.print(" with code ");
    //      Serial.println(code);
    //    }

    void onRead(BLECharacteristic* pCharacteristic) {
      Serial.print(pCharacteristic->getUUID().toString().c_str());
      Serial.print(": onRead(), value: ");
      Serial.println(pCharacteristic->getValue().c_str());
    };

    void onNotify(BLECharacteristic *pCharacteristic) {
      //uint8_t* pData;
      std::string pData = pCharacteristic->getValue();
      int len = pData.length();
      //        Serial.print("Notify callback for characteristic ");
      //        Serial.print(pCharacteristic->getUUID().toString().c_str());
      //        Serial.print(" of data length ");
      //        Serial.println(len);
      Serial.print("TX  ");
      for (int i = 0; i < len; i++) {
        Serial.printf("%02X ", pData[i]);
      }
      Serial.println();
    }

    void onWrite(BLECharacteristic *pCharacteristic) {
      //uint8_t* pData;
      std::string pData = pCharacteristic->getValue();
      int len = pData.length();
      // Serial.print("Write callback for characteristic ");
      // Serial.print(pCharacteristic->getUUID().toString().c_str());
      // Serial.print(" of data length ");
      // Serial.println(len);
      // Serial.print("RX  ");
      // for (int i = 0; i < len; i++) {         // leave this commented
      //   Serial.printf("%02X ", pData[i]);
      // }
      // Serial.println();

      if (pData[0] == 0xFB) {
        int pos = pData[1];
        for (int x = 0; x < len - 2; x++) {
          if (current) {
            updater[(pos * MTU) + x] = pData[x + 2];
          } else {
            updater2[(pos * MTU) + x] = pData[x + 2];
          }
        }

      } else if  (pData[0] == 0xFC) {
        if (current) {
          writeLen = (pData[1] * 256) + pData[2];
        } else {
          writeLen2 = (pData[1] * 256) + pData[2];
        }
        current = !current;
        cur = (pData[3] * 256) + pData[4];
        writeFile = true;
        if (cur < parts - 1) {
          request = !FASTMODE;
        }
      } else if (pData[0] == 0xFD) {
        sendMode = true;
        if (FLASH.exists("/update.bin")) {
          FLASH.remove("/update.bin");
        }
      } else if (pData[0] == 0xFE) {
        rParts = 0;
        tParts = (pData[1] * 256 * 256 * 256) + (pData[2] * 256 * 256) + (pData[3] * 256) + pData[4];

        Serial.print("Available space: ");
        Serial.println(FLASH.totalBytes() - FLASH.usedBytes());
        Serial.print("File Size: ");
        Serial.println(tParts);

      } else if  (pData[0] == 0xFF) {
        parts = (pData[1] * 256) + pData[2];
        MTU = (pData[3] * 256) + pData[4];
        MODE = UPDATE_MODE;

      } else if (pData[0] == 0xEF) {
        FLASH.format();
        sendSize = true;
      }



    }


};

static void writeBinary(fs::FS &fs, const char * path, uint8_t *dat, int len) {

  //Serial.printf("Write binary file %s\r\n", path);

  File file = fs.open(path, FILE_APPEND);

  if (!file) {
    Serial.println("- failed to open file for writing");
    return;
  }
  file.write(dat, len);
  file.close();
  writeFile = false;
  rParts += len;
}

void sendOtaResult(String result) {
  byte arr[result.length()];
  result.getBytes(arr, result.length());
  pCharacteristicTX->setValue(arr, result.length());
  pCharacteristicTX->notify();
  delay(200);
}


void performUpdate(Stream &updateSource, size_t updateSize) {
  char s1 = 0x0F;
  String result = String(s1);
  if (Update.begin(updateSize)) {
    size_t written = Update.writeStream(updateSource);
    if (written == updateSize) {
      Serial.println("Written : " + String(written) + " successfully");
    }
    else {
      Serial.println("Written only : " + String(written) + "/" + String(updateSize) + ". Retry?");
    }
    result += "Written : " + String(written) + "/" + String(updateSize) + " [" + String((written / updateSize) * 100) + "%] \n";
    if (Update.end()) {
      Serial.println("OTA done!");
      result += "OTA Done: ";
      if (Update.isFinished()) {
        Serial.println("Update successfully completed. Rebooting...");
        result += "Success!\n";
      }
      else {
        Serial.println("Update not finished? Something went wrong!");
        result += "Failed!\n";
      }

    }
    else {
      Serial.println("Error Occurred. Error #: " + String(Update.getError()));
      result += "Error #: " + String(Update.getError());
    }
  }
  else
  {
    Serial.println("Not enough space to begin OTA");
    result += "Not enough space for OTA";
  }
  if (deviceConnected) {
    sendOtaResult(result);
    delay(5000);
  }
}

void updateFromFS(fs::FS &fs) {
  File updateBin = fs.open("/update.bin");
  if (updateBin) {
    if (updateBin.isDirectory()) {
      Serial.println("Error, update.bin is not a file");
      updateBin.close();
      return;
    }

    size_t updateSize = updateBin.size();

    if (updateSize > 0) {
      Serial.println("Trying to start update");
      performUpdate(updateBin, updateSize);
    }
    else {
      Serial.println("Error, file is empty");
    }

    updateBin.close();

    // when finished remove the binary from spiffs to indicate end of the process
    Serial.println("Removing update file");
    fs.remove("/update.bin");

    rebootEspWithReason("Rebooting to complete OTA update");
  }
  else {
    Serial.println("Could not load update.bin from spiffs root");
  }
}

void initBLE() {
  BLEDevice::init("NimBLE OTA");
  BLEDevice::setMTU(517);
  BLEDevice::setPower(ESP_PWR_LVL_P9);
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristicTX = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ );
  pCharacteristicRX = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE_NR);
  pCharacteristicRX->setCallbacks(new MyCallbacks());
  pCharacteristicTX->setCallbacks(new MyCallbacks());
  pService->start();
  pServer->start();

  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  // this still is working for backward compatibility
  NimBLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  pAdvertising->start();
  //BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE OTA sketch");
  pinMode(BUILTINLED, OUTPUT);

  //SPI.begin(18, 22, 23, 5);       // For OTA with SD Card
  //SD.begin(5);                    // For OTA with SD Card

#ifdef USE_SPIFFS
  if (!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)) {
    Serial.println("SPIFFS Mount Failed");
    return;
  }
#else
  if (!FFat.begin()) {
    Serial.println("FFat Mount Failed");
    if (FORMAT_FFAT_IF_FAILED) FFat.format();
    return;
  }
#endif


  initBLE();

}

void loop() {

  switch (MODE) {

    case NORMAL_MODE:
      if (deviceConnected) {
        digitalWrite(BUILTINLED, HIGH);
        if (sendMode) {
          uint8_t fMode[] = {0xAA, FASTMODE};
          pCharacteristicTX->setValue(fMode, 2);
          pCharacteristicTX->notify();
          delay(50);
          sendMode = false;
        }
        if (sendSize) {
          unsigned long x = FLASH.totalBytes();
          unsigned long y = FLASH.usedBytes();
          uint8_t fSize[] = {0xEF, (uint8_t) (x >> 16), (uint8_t) (x >> 8), (uint8_t) x, (uint8_t) (y >> 16), (uint8_t) (y >> 8), (uint8_t) y};
          pCharacteristicTX->setValue(fSize, 7);
          pCharacteristicTX->notify();
          delay(50);
          sendSize = false;
        }

        // your loop code here
      } else {
        digitalWrite(BUILTINLED, LOW);
      }

      // or here

      break;

    case UPDATE_MODE:

      if (request) {
        uint8_t rq[] = {0xF1, (cur + 1) / 256, (cur + 1) % 256};
        pCharacteristicTX->setValue(rq, 3);
        pCharacteristicTX->notify();
        delay(50);
        request = false;
      }

      if (writeFile) {
        if (!current) {
          writeBinary(FLASH, "/update.bin", updater, writeLen);
        } else {
          writeBinary(FLASH, "/update.bin", updater2, writeLen2);
        }
        writeFile = false;
      }

      if (cur + 1 == parts) { // received complete file
        uint8_t com[] = {0xF2, (cur + 1) / 256, (cur + 1) % 256};
        pCharacteristicTX->setValue(com, 3);
        pCharacteristicTX->notify();
        delay(50);
        MODE = OTA_MODE;
      }

      break;

    case OTA_MODE:
      if (writeFile) {
        if (!current) {
          writeBinary(FLASH, "/update.bin", updater, writeLen);
        } else {
          writeBinary(FLASH, "/update.bin", updater2, writeLen2);
        }
      }


      if (rParts == tParts) {
        Serial.println("Complete");
        delay(5000);
        updateFromFS(FLASH);
      } else {
        writeFile = true;
        Serial.println("Incomplete");
        Serial.print("Expected: ");
        Serial.print(tParts);
        Serial.print("Received: ");
        Serial.println(rParts);
        delay(2000);
      }
      break;

  }

}
Download .txt
gitextract_ain1bw9_/

├── LICENSE
├── README.md
├── esp32_ble_ota/
│   └── esp32_ble_ota.ino
├── esp32_ble_ota_lib_compact/
│   ├── .gitignore
│   ├── .vscode/
│   │   ├── extensions.json
│   │   └── settings.json
│   ├── README.md
│   ├── discover.py
│   ├── include/
│   │   └── README
│   ├── lib/
│   │   ├── README
│   │   └── ble_ota_dfu/
│   │       ├── keywords.txt
│   │       ├── library.json
│   │       ├── library.properties
│   │       └── src/
│   │           ├── ble_ota_dfu.cpp
│   │           ├── ble_ota_dfu.hpp
│   │           ├── freertos_utils.cpp
│   │           └── freertos_utils.hpp
│   ├── ota_updater.py
│   ├── platformio.ini
│   ├── src/
│   │   ├── main.cpp
│   │   └── main.hpp
│   └── test/
│       └── README
└── esp32_nim_ble_ota/
    └── esp32_nim_ble_ota.ino
Download .txt
SYMBOL INDEX (12 symbols across 7 files)

FILE: esp32_ble_ota_lib_compact/discover.py
  function run (line 5) | async def run():

FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/ble_ota_dfu.cpp
  function task_install_update (line 7) | void task_install_update(void *parameters) {

FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/ble_ota_dfu.hpp
  class BLE_OTA_DFU (line 40) | class BLE_OTA_DFU
    method BLE_OTA_DFU (line 70) | BLE_OTA_DFU() = default;
  class BLEOverTheAirDeviceFirmwareUpdate (line 42) | class BLEOverTheAirDeviceFirmwareUpdate : public BLECharacteristicCallba...
  class BLE_OTA_DFU (line 62) | class BLE_OTA_DFU {
    method BLE_OTA_DFU (line 70) | BLE_OTA_DFU() = default;

FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/freertos_utils.cpp
  function BaseType_t (line 4) | BaseType_t xTaskCreatePinnedToCoreAndAssert(

FILE: esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/freertos_utils.hpp
  function _initialize_queue (line 15) | void _initialize_queue(QueueHandle_t *queue, const char *queue_name,

FILE: esp32_ble_ota_lib_compact/ota_updater.py
  function start_ota (line 26) | async def start_ota(ble_address: str, filename: str):
  function is_valid_address (line 178) | def is_valid_address(value: str = None) -> bool:

FILE: esp32_ble_ota_lib_compact/src/main.cpp
  function setup (line 7) | void setup() { ota_dfu_ble.begin("Test OTA DFU"); }
  function loop (line 12) | void loop() {
Condensed preview — 23 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (66K chars).
[
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2021 Felix Biego\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "README.md",
    "chars": 936,
    "preview": "# ESP32_BLE_OTA_Arduino\nOTA update on ESP32 via BLE\n\n- 1,038,544 bytes uploaded in 1min 25sec\n- Speed: ~ `12kb/s peak`\n\n"
  },
  {
    "path": "esp32_ble_ota/esp32_ble_ota.ino",
    "chars": 12744,
    "preview": "/*\r\n   MIT License\r\n\r\n   Copyright (c) 2021 Felix Biego\r\n\r\n   Permission is hereby granted, free of charge, to any perso"
  },
  {
    "path": "esp32_ble_ota_lib_compact/.gitignore",
    "chars": 94,
    "preview": ".pio\n.vscode/.browse.c_cpp.db*\n.vscode/c_cpp_properties.json\n.vscode/launch.json\n.vscode/ipch\n"
  },
  {
    "path": "esp32_ble_ota_lib_compact/.vscode/extensions.json",
    "chars": 274,
    "preview": "{\n    // See http://go.microsoft.com/fwlink/?LinkId=827846\n    // for the documentation about the extensions.json format"
  },
  {
    "path": "esp32_ble_ota_lib_compact/.vscode/settings.json",
    "chars": 111,
    "preview": "{\n    \"cSpell.words\": [\n        \"LOGD\",\n        \"LOGI\",\n        \"LOGW\",\n        \"ledc\",\n        \"LEDC\",\n    ]\n}"
  },
  {
    "path": "esp32_ble_ota_lib_compact/README.md",
    "chars": 493,
    "preview": "# Compact version of the BLE OTA example\n\nThis directory contains a PlatformIO project which implement a compact version"
  },
  {
    "path": "esp32_ble_ota_lib_compact/discover.py",
    "chars": 272,
    "preview": "import asyncio\nfrom bleak import BleakScanner\n\n\nasync def run():\n    for device in await BleakScanner.discover():\n      "
  },
  {
    "path": "esp32_ble_ota_lib_compact/include/README",
    "chars": 1386,
    "preview": "\nThis directory is intended for project header files.\n\nA header file is a file containing C declarations and macro defin"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/README",
    "chars": 1037,
    "preview": "\nThis directory is intended for project specific (private) libraries.\nPlatformIO will compile them to static libraries a"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/ble_ota_dfu/keywords.txt",
    "chars": 243,
    "preview": "# To be filled if you want to use it on Arduino    \n#FUNCTIONS COLOR \t\t\t#D35400 - ORANGE\t\t\tKEYWORD1\n#FUNCTIONS COLOR\t\t\t"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/ble_ota_dfu/library.json",
    "chars": 273,
    "preview": "{\n  \"name\": \"ble_ota_dfuU\",\n  \"keywords\": \"BLE OTA DFU\",\n  \"description\": \"BLE OTA DFU\",\n  \"repository\":\n  {\n    \"type\":"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/ble_ota_dfu/library.properties",
    "chars": 200,
    "preview": "name=ble_ota_dfu\nversion=1.0.0\nauthor=Vincent STRAGIER\nmaintainer=Vincent STRAGIER\nsentence=BLE OTA DFU\nparagraph=BLE OT"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/ble_ota_dfu.cpp",
    "chars": 13804,
    "preview": "/* Copyright 2022 Vincent Stragier */\n#include \"ble_ota_dfu.hpp\"\n\nQueueHandle_t start_update_queue;\nQueueHandle_t update"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/ble_ota_dfu.hpp",
    "chars": 2218,
    "preview": "/* Copyright 2022 Vincent Stragier */\n// Highly inspired by https://github.com/fbiego/ESP32_BLE_OTA_Arduino\n#pragma once"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/freertos_utils.cpp",
    "chars": 513,
    "preview": "/* Copyright 2022 Vincent Stragier */\n#include \"freertos_utils.hpp\"\n\nBaseType_t xTaskCreatePinnedToCoreAndAssert(\n    Ta"
  },
  {
    "path": "esp32_ble_ota_lib_compact/lib/ble_ota_dfu/src/freertos_utils.hpp",
    "chars": 1358,
    "preview": "/* Copyright 2022 Vincent Stragier */\n#pragma once\n#ifndef SRC_FREERTOS_UTILS_HPP_\n#define SRC_FREERTOS_UTILS_HPP_\n\n#inc"
  },
  {
    "path": "esp32_ble_ota_lib_compact/ota_updater.py",
    "chars": 9319,
    "preview": "from __future__ import print_function\nimport os\nimport asyncio\nimport sys\nimport re\nfrom time import sleep\n\nfrom bleak i"
  },
  {
    "path": "esp32_ble_ota_lib_compact/platformio.ini",
    "chars": 1268,
    "preview": "; PlatformIO Project Configuration File\n;\n;   Build options: build flags, source filter\n;   Upload options: custom uploa"
  },
  {
    "path": "esp32_ble_ota_lib_compact/src/main.cpp",
    "chars": 427,
    "preview": "/* Copyright 2022 Vincent Stragier */\n#include \"main.hpp\"\n\n///////////////////\n///    Setup    ///\n///////////////////\nv"
  },
  {
    "path": "esp32_ble_ota_lib_compact/src/main.hpp",
    "chars": 330,
    "preview": "/* Copyright 2022 Vincent Stragier */\n\n#ifndef SRC_MAIN_HPP_\n#define SRC_MAIN_HPP_\n///////////////////////\n///    Librar"
  },
  {
    "path": "esp32_ble_ota_lib_compact/test/README",
    "chars": 504,
    "preview": "\nThis directory is intended for PlatformIO Unit Testing and project tests.\n\nUnit Testing is a software testing method by"
  },
  {
    "path": "esp32_nim_ble_ota/esp32_nim_ble_ota.ino",
    "chars": 12538,
    "preview": "/*\n   MIT License\n   Copyright (c) 2021 Felix Biego\n   Permission is hereby granted, free of charge, to any person obtai"
  }
]

About this extraction

This page contains the full source code of the fbiego/ESP32_BLE_OTA_Arduino GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 23 files (60.0 KB), approximately 16.6k tokens, and a symbol index with 12 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!