I want to use OTA with my sketch and I have a esp32c6 with 4MB flash size.
So the OTA leaves me max 2MB of flash.
When compiled, my sketch goes slightly above 2MB (107%)
I guess that's because of the huge BLE library.
So I tried to migrate to NimBLE library which is smaller.
However, apparently NimBLE is not supported on this new hardware (esp32c6)
What else can I do ?
I am attaching the whole sketch here for any recommendations.
sketch.txt (24.1 KB)
#include <WebServer.h>
#include <Update.h>
#include <BLEDevice.h>
#include <BLEServer.h>
//#include <BLEUtils.h>
#include <Preferences.h>
Preferences preferences;
#ifdef __AVR__
#include <avr/power.h>
#endif
#include "Arduino.h"
#include <SPI.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <Adafruit_NeoPixel.h>
#define PIN 2
#define NUMPIXELS 12
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixelo = Adafruit_NeoPixel(1, 8, NEO_GRB + NEO_KHZ800);
unsigned long MyTimer = 0;
#include "WiFiProv.h"
#include "WiFi.h"
#include <ESPmDNS.h>
const char * pop = "abcd1234";
const char * service_name = "PROV_123";
const char * service_key = NULL;
bool reset_provisioned = true;
//BLE
BLEServer *pServer;
BLEService *pService;
#define bleServerName "ESP32_C6_ny"
bool deviceConnected = false;
bool messageReceivedComplete = false;
#define SERVICE_UUID "c0de0001-feed-f00d-c0ff-eeb3d05ebeef"
#define CHARACTERISTIC_UUID_TX "c0de0002-feed-f00d-c0ff-eeb3d05ebeef"
#define CHARACTERISTIC_UUID_RX "c0de0003-feed-f00d-c0ff-eeb3d05ebeef"
#define CHARACTERISTIC_UUID_RX2 "c0de0004-feed-f00d-c0ff-eeb3d05ebeef"
BLECharacteristic *pCharacteristicRX;
BLECharacteristic *pCharacteristicTX;
BLECharacteristic *pCharacteristicRX2;
BLEDescriptor bleDescriptor(BLEUUID((uint16_t)0x2902));
String message;
int r = 226, g = 101, b = 35;
int effect = 1, delay1 = 10, delay2 = 113;
float prcnt = 100;
int dir = 1;
struct colo {
uint8_t r, g, b;
};
colo rainbow[7];
int coloidx=0;
String ssid="0";
String wifipass="0";
WebServer serveru(81);
String loginIndex =
"<form name=loginForm>"
"<h1>ESP32 Login</h1>"
"<input name=userid placeholder='User ID'> "
"<input name=pwd placeholder=Password type=Password> "
"<input type=submit onclick=check(this.form) class=btn value=Login></form>"
"<script>"
"function check(form) {"
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
"{window.open('/serverIndex')}"
"else"
"{alert('Error Password or Username')}"
"}"
"</script>";
String serverIndex =
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
"<input type='file' name='update' id='file' onchange='sub(this)' style=display:none>"
"<label id='file-input' for='file'> Choose file...</label>"
"<input type='submit' class=btn value='Update'>"
"<br><br>"
"<div id='prg'></div>"
"<br><div id='prgbar'><div id='bar'></div></div><br></form>"
"<script>"
"function sub(obj){"
"var fileName = obj.value.split('\\\\');"
"document.getElementById('file-input').innerHTML = ' '+ fileName[fileName.length-1];"
"};"
"$('form').submit(function(e){"
"e.preventDefault();"
"var form = $('#upload_form')[0];"
"var data = new FormData(form);"
"$.ajax({"
"url: '/update',"
"type: 'POST',"
"data: data,"
"contentType: false,"
"processData:false,"
"xhr: function() {"
"var xhr = new window.XMLHttpRequest();"
"xhr.upload.addEventListener('progress', function(evt) {"
"if (evt.lengthComputable) {"
"var per = evt.loaded / evt.total;"
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
"$('#bar').css('width',Math.round(per*100) + '%');"
"}"
"}, false);"
"return xhr;"
"},"
"success:function(d, s) {"
"console.log('success!') "
"},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>";
WiFiServer server(80);
const char* base64Encoding = "YWRtaW46R3JhbmFkYTk."; // base64encoding of user & pass
String header;
unsigned long currentTime = millis();
unsigned long previousTime = 0;
const long timeoutTime = 5000;
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
void respond(String send_message){
pCharacteristicTX->setValue(send_message);
pCharacteristicTX->notify();
}
class ServerReadCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String rxValue = pCharacteristic->getValue();
/*
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++) {
Serial.print(rxValue[i]);
}
Serial.println();
*/
message = rxValue;
int cidx1 = message.indexOf(',');
int cidx2 = message.indexOf(',', cidx1 + 1);
String firstValue = message.substring(0, cidx1);
String secondValue = message.substring(cidx1 + 1, cidx2);
String thirdValue = message.substring(cidx2 + 1);
effect = firstValue.toInt();
delay1 = secondValue.toInt();
delay2 = thirdValue.toInt();
messageReceivedComplete = true;;
preferences.putInt("r", r);
preferences.putInt("g", g);
preferences.putInt("b", b);
preferences.putInt("effect", effect);
preferences.putInt("delay1", delay1);
preferences.putInt("delay2", delay2);
}
};
class ServerReadCallbacks2: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String rxValue = pCharacteristic->getValue();
uint8_t cc[3];
r=rxValue[0];
g=rxValue[1];
b=rxValue[2];
preferences.putInt("r", r);
preferences.putInt("g", g);
preferences.putInt("b", b);
preferences.putInt("effect", effect);
preferences.putInt("delay1", delay1);
preferences.putInt("delay2", delay2);
/*
//COlor parse
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++) {
cc[i]=rxValue[i];
Serial.println(cc[i]);
//Serial.print(rxValue[i]);
}
RGB CCOLOR = {cc[0], cc[1], cc[2]};
setColor(CCOLOR);
Serial.println();
String colo;
colo = rxValue;
Serial.println(colo);
*/
}
};
void SysProvEvent(arduino_event_t *sys_event) {
switch (sys_event->event_id) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
Serial.print("\nConnected IP address : ");
Serial.println(IPAddress(sys_event->event_info.got_ip.ip_info.ip.addr));
startServers();
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: Serial.println("\nDisconnected. Connecting to the AP again... "); break;
case ARDUINO_EVENT_PROV_START: Serial.println("\nProvisioning started\nGive Credentials of your access point using smartphone app"); break;
case ARDUINO_EVENT_PROV_CRED_RECV:
{
/*
Serial.println("\nReceived Wi-Fi credentials");
Serial.print("\tSSID : ");
Serial.println((const char *)sys_event->event_info.prov_cred_recv.ssid);
Serial.print("\tPassword : ");
Serial.println((char const *)sys_event->event_info.prov_cred_recv.password);
*/
ssid = (const char *)sys_event->event_info.prov_cred_recv.ssid;
wifipass = (char const *)sys_event->event_info.prov_cred_recv.password;
preferences.putString("ssid", ssid);
preferences.putString("wifipass", wifipass);
break;
}
case ARDUINO_EVENT_PROV_CRED_FAIL:
{
Serial.println("\nProvisioning failed!\nPlease reset to factory and retry provisioning\n");
if (sys_event->event_info.prov_fail_reason == NETWORK_PROV_WIFI_STA_AUTH_ERROR) {
//Serial.println("\nWi-Fi AP password incorrect");
} else {
//Serial.println("\nWi-Fi AP not found....Add API \" nvs_flash_erase() \" before beginProvision()");
}
break;
}
case ARDUINO_EVENT_PROV_CRED_SUCCESS: Serial.println("\nProvisioning Successful"); break;
case ARDUINO_EVENT_PROV_END: Serial.println("\nProvisioning Ends"); break;
default: break;
}
}
void setup() {
rainbow[0] = {148, 0, 211};
rainbow[1] = {75, 0, 130};
rainbow[2] = {0, 0, 255};
rainbow[3] = {0, 255, 0};
rainbow[4] = {255, 255, 0};
rainbow[5] = {255, 127, 0};
rainbow[6] = {255, 0, 0};
delay(1000);
//#define FPSerial Serial2
Serial1.begin(9600, SERIAL_8N1, /*rx =*/16, /*tx =*/17);
delay(1000);
Serial.begin(115200);
delay(1000);
Serial.println("\n starting...\n");
Serial.begin(115200);
preferences.begin("my-app", false);
r=preferences.getInt("r", 100);
g=preferences.getInt("g", 100);
b=preferences.getInt("b", 100);
effect=preferences.getInt("effect", 1);
delay1=preferences.getInt("delay1", 50);
delay2=preferences.getInt("delay2", 100);
ssid=preferences.getString("ssid", "0");
wifipass=preferences.getString("wifipass", "0");
if(ssid!="0") {
ConnectToWiFi();
startServers();
} else {
startBLEGATT();
}
Serial.println("SPI init ...");
SPI.begin();
Serial.println("Pixel Leds init ...");
pixelo.begin();
pixelo.setPixelColor(0, pixels.Color(0,0,0));
pixelo.show();
pixels.begin();
pixels.show();
pixels.setPixelColor(0, pixels.Color(0,25,0));
pixels.show();
for (int i = 0; i < NUMPIXELS; i++) {
delay(50);
pixels.setPixelColor(i, pixels.Color(0,0,0));
pixels.setPixelColor(i+1, pixels.Color(0,25,0));
pixels.show();
}
}
void loop() {
serveru.handleClient();
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') {
if (currentLine.length() == 0) {
if (header.indexOf(base64Encoding)>=0)
{
boolean jsonOut=false;
if(header.indexOf("application/json")>=0) {
jsonOut=true;
client.println("HTTP/1.1 200 OK");
client.println("Content-type:application/json");
//client.println("Connection: close");
client.println();
} else {
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
//client.println("Connection: close");
client.println();
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #555555;} .button3 {background-color: #aa8800;}</style></head>");
client.println("<body><h1>Color Lamp</h1>");
}
if (header.indexOf("GET /effect") >= 0) {
int idx = header.indexOf("GET /effect")+12;
int idx2 = header.indexOf(" HTTP");
String message=header.substring(idx,idx2);
int cidx1 = message.indexOf(',');
int cidx2 = message.indexOf(',', cidx1 + 1);
String firstValue = message.substring(0, cidx1);
String secondValue = message.substring(cidx1 + 1, cidx2);
String thirdValue = message.substring(cidx2 + 1);
effect = firstValue.toInt();
delay1 = secondValue.toInt();
delay2 = thirdValue.toInt();
preferences.putInt("r", r);
preferences.putInt("g", g);
preferences.putInt("b", b);
preferences.putInt("effect", effect);
preferences.putInt("delay1", delay1);
preferences.putInt("delay2", delay2);
Serial.println("Got values :"+ message);
if(!jsonOut) client.println("<p>Got values :"+message+"</p>");
if(jsonOut) client.println("{values: \"200\"}");
} else if (header.indexOf("GET /color") >= 0) {
int idx = header.indexOf("GET /color")+11;
int idx2 = header.indexOf(" HTTP");
String message=header.substring(idx,idx2);
int cidx1 = message.indexOf(',');
int cidx2 = message.indexOf(',', cidx1 + 1);
String firstValue = message.substring(0, cidx1);
String secondValue = message.substring(cidx1 + 1, cidx2);
String thirdValue = message.substring(cidx2 + 1);
r = firstValue.toInt();
g = secondValue.toInt();
b = thirdValue.toInt();
preferences.putInt("r", r);
preferences.putInt("g", g);
preferences.putInt("b", b);
preferences.putInt("effect", effect);
preferences.putInt("delay1", delay1);
preferences.putInt("delay2", delay2);
Serial.println("Got values :"+ message);
if(!jsonOut) client.println("<p>Got values :"+message+"</p>");
if(jsonOut) client.println("{values: \"200\"}");
} else if (header.indexOf("GET /bleon") >= 0) {
if(!jsonOut) client.println("<p>Turning BLE ON !</p>");
if(jsonOut) client.println("{bleon: \"200\"}");
preferences.putString("ssid", "0");
preferences.putString("wifipass", "0");
startBLEGATT();
} else if (header.indexOf("GET /on") >= 0) {
if(!jsonOut) client.println("<p>Turning ON !</p>");
if(jsonOut) client.println("{on: \"200\"}");
effect = 2;
delay1 = 500;
delay2 = 100;
} else if (header.indexOf("GET /off") >= 0) {
if(!jsonOut) client.println("<p>Turning OFF !</p>");
if(jsonOut) client.println("{off: \"200\"}");
effect = 0;
delay1 = 0;
delay2 = 0;
} else {
Serial.println("Command not found !");
if(!jsonOut) client.println("<p>Command not found !</p>");
if(jsonOut) client.println("{none: \"200\"}");
}
if(!jsonOut) {
client.println("<p><a href=\"/on\"><button class=\"button\">ON</button></a>");
client.println("<a href=\"/off\"><button class=\"button button2\">OFF</button></a></p>");
client.println("<p><a href=\"/bleon\"><button class=\"button\">BLE ON</button></a></p>");
client.println("</body></html>");
}
// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
}
else{
client.println("HTTP/1.1 401 Unauthorized");
client.println("WWW-Authenticate: Basic realm=\"Secure\"");
client.println("Content-Type: text/html");
client.println();
client.println("<html>Authentication failed</html>");
}
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
if(effect == 999) {
effect=0;
preferences.putInt("effect", effect);
pServer->getAdvertising()->stop();
delay(100);
pService->stop();
BLEDevice::deinit(true);
delay(500);
startWifiProv();
}
if(effect == 1) {
for(int i=0; i<NUMPIXELS; i++) {
int flicker = random(0,55);
int r1 = r-flicker;
int g1 = g-flicker;
int b1 = b-flicker;
if(g1<0) g1=0;
if(r1<0) r1=0;
if(b1<0) b1=0;
pixels.setPixelColor(i,r1,g1, b1);
}
pixels.show();
if(deviceConnected && messageReceivedComplete){
messageReceivedComplete = false;
if(String("hello") == message){
respond(String("world"));
Serial.println("sent world");
}else{
respond(message);
Serial.println("echoed");
}
}
delay(random(delay1,delay2));
} else if (effect == 0) {
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i,0,0,0);
}
pixels.show();
delay(500);
} else if (effect == 2) {
for(int i=0; i<NUMPIXELS; i++) {
int r1 = int(r*(prcnt/100));
int g1 = int(g*(prcnt/100));
int b1 = int(b*(prcnt/100));
if(g1<0) g1=0;
if(r1<0) r1=0;
if(b1<0) b1=0;
pixels.setPixelColor(i,r1,g1,b1);
}
prcnt=prcnt-(delay2*dir);
if(prcnt<0) {
prcnt=0;
dir=-dir;
}
if(prcnt>100) {
prcnt=100;
dir=-dir;
}
pixels.show();
delay(delay1);
} else if (effect == 3) {
for(int i=0; i<NUMPIXELS; i++) {
int r1 = int(rainbow[coloidx].r*(prcnt/100));
int g1 = int(rainbow[coloidx].g*(prcnt/100));
int b1 = int(rainbow[coloidx].b*(prcnt/100));
if(g1<0) g1=0;
if(r1<0) r1=0;
if(b1<0) b1=0;
pixels.setPixelColor(i, r1, g1, b1);
}
prcnt=prcnt-(delay2*dir);
if(prcnt<0) {
prcnt=0;
dir=-dir;
if(coloidx<6) {
coloidx++;
} else {coloidx=0;}
}
if(prcnt>100) {
prcnt=100;
dir=-dir;
}
pixels.show();
delay(delay1);
}
}
void startServers() {
if (MDNS.begin("myled")) {
Serial.println("mDNS responder started");
} else {
Serial.println("Error setting up MDNS responder!");
}
server.begin();
Serial.println("HTTP server started");
serveru.on("/", HTTP_GET, []() {
serveru.sendHeader("Connection", "close");
serveru.send(200, "text/html", loginIndex);
});
serveru.on("/serverIndex", HTTP_GET, []() {
serveru.sendHeader("Connection", "close");
serveru.send(200, "text/html", serverIndex);
});
/*handling uploading firmware file */
serveru.on("/update", HTTP_POST, []() {
serveru.sendHeader("Connection", "close");
serveru.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = serveru.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
serveru.begin();
}
void startBLEGATT() {
BLEDevice::init(bleServerName);
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
pService = pServer->createService(SERVICE_UUID);
pCharacteristicRX = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
bleDescriptor.setValue("BLE Value");
pCharacteristicRX->addDescriptor(&bleDescriptor);
pCharacteristicRX->setCallbacks(new ServerReadCallbacks());
pCharacteristicTX = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristicRX2 = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX2,
BLECharacteristic::PROPERTY_WRITE
);
bleDescriptor.setValue("BLE Value");
pCharacteristicRX2->addDescriptor(&bleDescriptor);
pCharacteristicRX2->setCallbacks(new ServerReadCallbacks2());
pCharacteristicTX = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristicTX->addDescriptor(&bleDescriptor);
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to BLE...");
}
void startWifiProv() {
WiFi.begin(); // no SSID/PWD - get it from the Provisioning APP or from NVS (last successful connection)
WiFi.onEvent(SysProvEvent);
// BLE Provisioning using the ESP SoftAP Prov works fine for any BLE SoC, including ESP32, ESP32S3 and ESP32C3.
Serial.println("Begin Provisioning using BLE");
// Sample uuid that user can pass during provisioning using BLE
uint8_t uuid[16] = {0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf, 0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02};
WiFiProv.beginProvision(
NETWORK_PROV_SCHEME_BLE, NETWORK_PROV_SCHEME_HANDLER_FREE_BLE, NETWORK_PROV_SECURITY_1, pop, service_name, service_key, uuid, reset_provisioned
);
log_d("ble qr");
WiFiProv.printQR(service_name, pop, "ble");
}
void ConnectToWiFi() {
WiFi.mode(WIFI_STA);
Serial.println("WiFi.mode(WIFI_STA)");
int myCount = 0;
Serial.print("trying to connect to #");
Serial.print(ssid);
Serial.println("#");
WiFi.begin(ssid, wifipass);
while (WiFi.status() != WL_CONNECTED && myCount < 20) {
yield();
if ( TimePeriodIsOver(MyTimer, 500) ) { // once every 500 miliseconds
Serial.print("."); // print a dot
myCount++;
if (myCount > 240) { // after 120 dots = 60 seconds restart
Serial.println();
Serial.print("not yet connected");
}
}
}
if (WiFi.status() == WL_CONNECTED ) {
Serial.println("");
Serial.print("Connected to #");
Serial.print(ssid);
Serial.print("# IP address: ");
Serial.println(WiFi.localIP());
delay(200);
} else {
Serial.print("Not Connected to #");
startBLEGATT();
}
}
boolean TimePeriodIsOver (unsigned long &periodStartTime, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - periodStartTime >= TimePeriod )
{
periodStartTime = currentMillis; // set new expireTime
return true; // more time than TimePeriod) has elapsed since last time if-condition was true
}
else return false; // not expired
}