Skip to content

Instantly share code, notes, and snippets.

@thankthemaker
Created June 9, 2021 16:00
Show Gist options
  • Save thankthemaker/b91b47f0e6b773d23a3077e859ea0f72 to your computer and use it in GitHub Desktop.
Save thankthemaker/b91b47f0e6b773d23a3077e859ea0f72 to your computer and use it in GitHub Desktop.
rESCue OTA only
#include "Arduino.h"
#include <NimBLEDevice.h>
#include "esp_ota_ops.h"
#include <Preferences.h>
#include <ArduinoJson.h>
#define SOFTWARE_VERSION_MAJOR 1
#define SOFTWARE_VERSION_MINOR 0
#define SOFTWARE_VERSION_PATCH 0
#define HARDWARE_VERSION_MAJOR 3
#define HARDWARE_VERSION_MINOR 1
#define SERVICE_UUID_ESPOTA "d804b643-6ce7-4e81-9f8a-ce0f699085eb"
#define CHARACTERISTIC_UUID_ID "d804b644-6ce7-4e81-9f8a-ce0f699085eb"
#define CHARACTERISTIC_UUID_CONF "d804b645-6ce7-4e81-9f8a-ce0f699085eb"
#define SERVICE_UUID_OTA "c8659210-af91-4ad3-a995-a58d6fd26145" // UART service UUID
#define CHARACTERISTIC_UUID_FW "c8659211-af91-4ad3-a995-a58d6fd26145"
#define CHARACTERISTIC_UUID_HW_VERSION "c8659212-af91-4ad3-a995-a58d6fd26145"
#define FULL_PACKET 512
#define CHARPOS_UPDATE_FLAG 5
int numberPixelLight = 0;
int numberPixelBatMon = 0;
int vescId = 0;
String authToken = "";
String wifiPassword = "";
String local_name;
BLEServer *pServer = NULL;
BLEService *pESPOTAService = NULL;
BLECharacteristic *pESPOTAIdCharacteristic = NULL;
BLECharacteristic *pESPOTAConfCharacteristic = NULL;
BLEService *pService = NULL;
BLECharacteristic *pVersionCharacteristic = NULL;
BLECharacteristic *pOtaCharacteristic = NULL;
esp_ota_handle_t otaHandler = 0;
bool updateFlag = false;
bool readyFlag = false;
int bytesReceived = 0;
int timesWritten = 0;
uint32_t frameNumber = 0;
Preferences preferences;
struct Config {
boolean otaUpdateActive = true;
boolean isNotificationEnabled = false;
double minBatteryVoltage = 41.0;
double maxBatteryVoltage = 50.4;
int startSoundIndex = 0;
int startLightIndex = 0;
int batteryWarningSoundIndex = 406;
int batteryAlarmSoundIndex = 402;
int startLightDuration = 1000;
int idleLightIndex = 0;
int lightFadingDuration = 50;
int lightMaxBrightness = 100;
int lightColorPrimary = 0;
int lightColorPrimaryRed = 0;
int lightColorPrimaryGreen = 0;
int lightColorPrimaryBlue = 0;
int lightColorSecondary = 0;
int lightColorSecondaryRed = 0;
int lightColorSecondaryGreen = 0;
int lightColorSecondaryBlue = 0;
boolean brakeLightEnabled = true;
int brakeLightMinAmp = 4;
int numberPixelLight = 32;
int numberPixelBatMon = 5;
int vescId = 25;
String authToken;
} config;
void readPreferences() {
printf("readPreferences: ");
preferences.begin("rESCue", true);
String json = preferences.getString("config", "");
StaticJsonDocument<1024> doc;
deserializeJson(doc, json);
Serial.println("readPreferences: " + json);
config.otaUpdateActive = doc["otaUpdateActive"] | true;
config.isNotificationEnabled = doc["isNotificationEnabled"] | false;
config.minBatteryVoltage = doc["minBatteryVoltage"] | 40.0;
config.maxBatteryVoltage = doc["maxBatteryVoltage"] | 50.4;
config.startSoundIndex = doc["startSoundIndex"] | 107;
config.startLightIndex = doc["startLightIndex"] | 1;
config.batteryWarningSoundIndex = doc["batteryWarningSoundIndex"] | 406;
config.batteryAlarmSoundIndex = doc["batteryAlarmSoundIndex"] | 402;
config.startLightDuration = doc["startLightDuration"] | 1000;
config.lightColorPrimary = doc["lightColorPrimary"] | 0xFFFFFF;
config.lightColorSecondary = doc["lightColorSecondary"] | 0xFF0000;
config.idleLightIndex = doc["idleLightIndex"] | 0;
config.lightFadingDuration = doc["lightFadingDuration"] | 220;
config.lightMaxBrightness = doc["lightMaxBrightness"] | 100;
config.brakeLightEnabled = doc["brakeLightEnabled"] | true;
config.brakeLightMinAmp = doc["brakeLightMinAmp"] | 4;
config.authToken = doc["authToken"] | "";
config.vescId = doc["vescId"] | 25;
config.numberPixelLight = doc["numberPixelLight"] | 16;
config.numberPixelBatMon = doc["numberPixelBatMon"] | 5;
// calculate RGB values for primary and secondary color
config.lightColorPrimaryRed = (config.lightColorPrimary >> 16) & 0x0ff;
config.lightColorPrimaryGreen = (config.lightColorPrimary >> 8) & 0x0ff;
config.lightColorPrimaryBlue = config.lightColorPrimary & 0x0ff;
config.lightColorSecondaryRed = (config.lightColorSecondary >> 16) & 0x0ff;
config.lightColorSecondaryGreen = (config.lightColorSecondary >> 8) & 0x0ff;
config.lightColorSecondaryBlue = config.lightColorSecondary & 0x0ff;
preferences.end();
}
void savePreferences() {
printf("savePreferences: ");
preferences.begin("rESCue", false);
StaticJsonDocument<1024> doc;
doc["otaUpdateActive"] = config.otaUpdateActive;
doc["isNotificationEnabled"] = config.isNotificationEnabled;
doc["minBatteryVoltage"] = config.minBatteryVoltage;
doc["maxBatteryVoltage"] = config.maxBatteryVoltage;
doc["startSoundIndex"] = config.startSoundIndex;
doc["startLightIndex"] = config.startLightIndex;
doc["batteryWarningSoundIndex"] = config.batteryWarningSoundIndex;
doc["batteryAlarmSoundIndex"] = config.batteryAlarmSoundIndex;
doc["startLightDuration"] = config.startLightDuration;
doc["lightColorPrimary"] = config.lightColorPrimary;
doc["lightColorSecondary"] = config.lightColorSecondary;
doc["idleLightIndex"] = config.idleLightIndex;
doc["lightFadingDuration"] = config.lightFadingDuration;
doc["lightMaxBrightness"] = config.lightMaxBrightness;
doc["brakeLightEnabled"] = config.brakeLightEnabled;
doc["brakeLightMinAmp"] = config.brakeLightMinAmp;
doc["authToken"] = config.authToken;
doc["vescId"] = config.vescId;
doc["numberPixelLight"] = config.numberPixelLight;
doc["numberPixelBatMon"] = config.numberPixelBatMon;
String json = "";
serializeJson(doc, json);
Serial.println("savePreferences: " + json);
preferences.putString("config", json);
preferences.end();
}
NimBLEUUID getConfCharacteristicsUuid() {
return pESPOTAConfCharacteristic->getUUID();
}
class OTACallback: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxData = pCharacteristic->getValue();
if(pCharacteristic->getUUID().equals(getConfCharacteristicsUuid())) {
//Serial.println("Write config");
//Serial.println("String " + String(rxData.c_str()));
//Serial.println("Length " + String(rxData.length()));
std::string str(rxData.c_str());
std::string::size_type middle = str.find('='); // Find position of ','
std::string key = "";
std::string value = "";
if(middle != std::string::npos) {
key = str.substr(0, middle);
value = str.substr(middle + 1, str.size() - (middle + 1));
}
Serial.println(String(key.c_str()) + String("=") + String(value.c_str()));
if(key == "numberPixelLight") {
config.numberPixelLight = atoi(value.c_str());
}
if(key == "numberPixelBatMon") {
config.numberPixelBatMon = atoi(value.c_str());
}
if(key == "vescId") {
config.vescId = atoi(value.c_str());
}
if(key == "authToken") {
config.authToken = value.c_str();
}
if(key == "save") {
savePreferences();
delay(100);
}
} else {
if (!updateFlag) { //If it's the first packet of OTA since bootup, begin OTA
Serial.println("\nBeginOTA");
const esp_partition_t *partition = esp_ota_get_next_update_partition(NULL);
Serial.println("Selected OTA partiton:");
Serial.println("partition label:" + String(partition->label));
Serial.println("partition size:" + String(partition->size));
esp_ota_begin(partition, OTA_SIZE_UNKNOWN, &otaHandler);
updateFlag = true;
}
// if (_p_ble != NULL) {
if (rxData.length() > 0) {
Serial.print("Got frame " + String(frameNumber));
esp_ota_write(otaHandler, rxData.c_str(), rxData.length());
if (rxData.length() != FULL_PACKET) {
esp_ota_end(otaHandler);
Serial.println("\nEndOTA");
const esp_partition_t *partition = esp_ota_get_next_update_partition(NULL);
if (ESP_OK == esp_ota_set_boot_partition(partition)) {
Serial.println("Activate partiton:");
Serial.println("partition label:" + String(partition->label));
Serial.println("partition size:" + String(partition->size));
delay(2000);
esp_restart();
} else {
Serial.println("Upload Error");
}
}
}
// }
delay(5); // needed to give BLE stack some time
uint8_t txdata[4] = { (uint8_t)(frameNumber >> 24), (uint8_t)(frameNumber >> 16), (uint8_t)(frameNumber >> 8), (uint8_t)frameNumber};
pCharacteristic->setValue((uint8_t *) txdata, 4);
pCharacteristic->notify();
Serial.println(", Ack. frame no. " + String(frameNumber++));
}
}
};
bool begin(const char* localName = "UART Service") {
// Create the BLE Device
BLEDevice::init(localName);
// Create the BLE Server
pServer = BLEDevice::createServer();
// pServer->setCallbacks(new BLECustomServerCallbacks());
// Create the BLE Service
pESPOTAService = pServer->createService(SERVICE_UUID_ESPOTA);
pService = pServer->createService(SERVICE_UUID_OTA);
// Create a BLE Characteristic
pESPOTAIdCharacteristic = pESPOTAService->createCharacteristic(
CHARACTERISTIC_UUID_ID,
NIMBLE_PROPERTY::READ
);
pESPOTAConfCharacteristic = pESPOTAService->createCharacteristic(
CHARACTERISTIC_UUID_CONF,
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::WRITE
);
pVersionCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_HW_VERSION,
NIMBLE_PROPERTY::READ
);
pOtaCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_FW,
NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::WRITE
);
pESPOTAConfCharacteristic->setCallbacks(new OTACallback());
pOtaCharacteristic->setCallbacks(new OTACallback());
// Start the service(s)
pESPOTAService->start();
pService->start();
// Start advertising
pServer->getAdvertising()->addServiceUUID(SERVICE_UUID_ESPOTA);
pServer->getAdvertising()->start();
uint8_t hardwareVersion[5] = {HARDWARE_VERSION_MAJOR, HARDWARE_VERSION_MINOR, SOFTWARE_VERSION_MAJOR, SOFTWARE_VERSION_MINOR, SOFTWARE_VERSION_PATCH};
pVersionCharacteristic->setValue((uint8_t*)hardwareVersion, 5);
return true;
}
void setup() {
Serial.begin(115200);
begin("rESCue OTA Updates");
// Get Partitionsizes
size_t ul;
esp_partition_iterator_t _mypartiterator;
const esp_partition_t *_mypart;
ul = spi_flash_get_chip_size();
Serial.print("\nFlash chip size: ");
Serial.println(ul);
Serial.println("Partition table:");
_mypartiterator = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);
while (_mypartiterator != NULL) {
_mypart = esp_partition_get(_mypartiterator);
printf("Type: %02x SubType %02x Address 0x%06X Size 0x%06X Encryption %i Label %s\r\n", _mypart->type, _mypart->subtype, _mypart->address, _mypart->size, _mypart->encrypted, _mypart->label);
_mypartiterator = esp_partition_next(_mypartiterator);
}
_mypart = esp_ota_get_boot_partition();
printf("Current active partition is %s\r\n", _mypart->label);
readPreferences();
}
void loop() {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment