Some string messages are not being sent over BLE

Hello,

Is there anyone with extensive experience working with the BLE library for ESP32 and Bluetooth Low Energy? I am testing the code below. The code is working because necessary messages, such as the request for SSID and password, are displayed. User input from the connected device is successfully received by the ESP, and a Wi-Fi connection can be established. However, the problem is that not all messages are sent or displayed within the connected device (custom app). I suspect the problem lies within the Arduino code, since I tested this code with both nRF Connect and Serial Bluetooth Terminal apps. In both cases, the same messages are not displayed as within the custom app. The messages that are not displayed are:

"Great! Your WiFi name is: %s", wifi_name.c_str()

"Great! WiFi password was successfully received. I have all the info that I need."

"Please wait a moment while we try to connect to WiFi."

"Connecting to WiFi was not successful. I will try again!"

Is there anyone who can tell me what I am doing wrong? I have tried everything I could find online, but nothing seems to work.

I would be extremely grateful for any advice. Also I am using the esp32 s3 dev board.

#include <BLEDevice.h>
#include <BLEServer.h>
#include <WiFi.h>

#define SERVICE_UUID        "CD9CFC21-0ECC-42E5-BF22-48AA715CA112"
#define CHARACTERISTIC_UUID "66E5FFCE-AA96-4DC9-90C3-C62BBCCD29AC"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
static String wifi_name;
static String wifi_pass;
static String user_uuid_var;    
uint8_t setupStep = 0;
bool uuidReceived = false;      

void sendBLEMessage(const String& message) {
  if (deviceConnected && pCharacteristic) {
    pCharacteristic->setValue(message.c_str());
    pCharacteristic->notify();
    delay(10);
    Serial.println("SENT: " + message);
  } else {
    Serial.println("Cannot send message: Device not connected or characteristic not initialized.");
  }
}

class ServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
    setupStep = 0;
    uuidReceived = false;
    Serial.println("Device connected, waiting for UUID...");
  }
  
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
    BLEDevice::startAdvertising();
    Serial.println("Device disconnected");
  }
};

class CharacteristicCallbacks: public BLECharacteristicCallbacks {
  public:
    static unsigned long messageStartTime;

    void onWrite(BLECharacteristic *pCharacteristic) {
      if (!pCharacteristic->getValue().length()) {
        sendBLEMessage("Error: Received empty command.");
        Serial.println("Received empty value. Ignoring.");
        return;
      }

      String value = pCharacteristic->getValue().c_str();

      if (!uuidReceived) {
        user_uuid_var = value;
        uuidReceived = true;
        Serial.print("Received UUID: ");
        Serial.println(user_uuid_var);
        delay(100);
        sendBLEMessage("Hello! This is your GreenWateringIRI25 irrigation system. WiFi setup is required. Type 'OK' to continue.");
        return;
      }

      switch(setupStep) {
        case 0:
          if(value == "OK") {
              sendBLEMessage("Please type WiFi SSID (WiFi name)?");
              setupStep = 1;
              Serial.println("Received OK, asking for SSID");
          }
          break;

        case 1:
          wifi_name = value;
          char messageBuffer[100];
          snprintf(messageBuffer, sizeof(messageBuffer), "Great! Your WiFi name is: %s", wifi_name.c_str());
          sendBLEMessage(messageBuffer);
          delay(4000);
          sendBLEMessage("Please type your WiFi password?");
          setupStep = 2;
          Serial.println("Received SSID: " + wifi_name);
          break;

        case 2:
          wifi_pass = value;
          sendBLEMessage("Great! WiFi password was successfully received. I have all the Info that I need.");
          delay(4000); 
          sendBLEMessage("Please wait a moment while we try to connect to WiFi.");

          Serial.println("Received password, attempting WiFi connection");

          WiFi.begin(wifi_name.c_str(), wifi_pass.c_str());
          int tries = 0;
          const int maxTries = 3;
          while (WiFi.status() != WL_CONNECTED && tries < maxTries) {
            delay(2000);
            tries++;
            Serial.print("WiFi connection attempt ");
            Serial.print(tries);
            Serial.println(" of " + String(maxTries) + " failed, retrying");
            sendBLEMessage("Connecting to WiFi was not successful. I will try again!");
          }

          if(WiFi.status() == WL_CONNECTED){
            sendBLEMessage("Connecting to WiFi was successful! You can disconnect me from Bluetooth!");
            setupStep = 3;
            Serial.println("WiFi connected successfully");
          } else {
            sendBLEMessage("Connecting to WiFi was not successful after all attempts. Try to reconnect the phone with GreenWateringIRI25 device and send WiFi credentials again!");
            setupStep = 0;
            Serial.println("WiFi connection failed after all attempts");
          }
          break;
      }
    }
};

unsigned long CharacteristicCallbacks::messageStartTime = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");

  BLEDevice::init("GreenWateringIRI25");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new ServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
    CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ |
    BLECharacteristic::PROPERTY_WRITE |
    BLECharacteristic::PROPERTY_NOTIFY
  );
  pCharacteristic->setCallbacks(new CharacteristicCallbacks());

  pService->start();
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  BLEDevice::startAdvertising();
  Serial.println("BLE setup complete, waiting for connections...");
}

void loop() {
  delay(50);
}

Give examples of successfully-sent stings.

You can’t define a new variable within a case without a compound statement around the content of the case.

Also this local value is short lived, not sure if the underlying library makes copy of the data or just use asynchronously a pointer that could go stale.

Try with a global buffer to see if there is a difference

Do i send pictures or just which strings are displayed?

I change it but it is the same as before?

Post the modified code

Strings. Post them in a code block. Your "failing" strings are over 50 characters. How long are the "good" strings? Looks like the buffer is being discussed above.

RTFM

For notifications to work with subscription by the phone, your #includes should be

#include <BLEDevice.h>
#include <BLEServer.h>
#include <WiFi.h>
#include <BLEUtils.h>//add
#include <BLE2902.h>//add

Then add the descriptor here in setup()

 pCharacteristic->setCallbacks(new CharacteristicCallbacks());
  pCharacteristic->addDescriptor(new BLE2902());//add  
  pService->start();

What is very important for the long messages you send is to set the "requestMTU" in the phone app to maximum (517) or some other value longer than your messages.

With these changes, all the SENT messages are received by the phone. I was using LightBlue on an Android phone.

#include <BLEDevice.h>
#include <BLEServer.h>
#include <WiFi.h>
#include <BLEUtils.h>//add
#include <BLE2902.h>//add

#define SERVICE_UUID        "CD9CFC21-0ECC-42E5-BF22-48AA715CA112"
#define CHARACTERISTIC_UUID "66E5FFCE-AA96-4DC9-90C3-C62BBCCD29AC"

BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
static String wifi_name;
static String wifi_pass;
static String user_uuid_var;
uint8_t setupStep = 0;
bool uuidReceived = false;

void sendBLEMessage(const String& message) {
  if (deviceConnected && pCharacteristic) {
    pCharacteristic->setValue(message.c_str());
    pCharacteristic->notify();
    delay(10);
    Serial.println("SENT: " + message);
  } else {
    Serial.println("Cannot send message: Device not connected or characteristic not initialized.");
  }
}

class ServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
      setupStep = 0;
      uuidReceived = false;
      Serial.println("Device connected, waiting for UUID...");
    }

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

class CharacteristicCallbacks: public BLECharacteristicCallbacks {
  public:
    static unsigned long messageStartTime;

    void onWrite(BLECharacteristic *pCharacteristic) {
      if (!pCharacteristic->getValue().length()) {
        sendBLEMessage("Error: Received empty command.");
        Serial.println("Received empty value. Ignoring.");
        return;
      }

      String value = pCharacteristic->getValue().c_str();

      if (!uuidReceived) {
        user_uuid_var = value;
        uuidReceived = true;
        Serial.print("Received UUID: ");
        Serial.println(user_uuid_var);
        delay(100);
        sendBLEMessage("Hello! This is your GreenWateringIRI25 irrigation system. WiFi setup is required. Type 'OK' to continue.");
        return;
      }

      switch (setupStep) {
        case 0:
          if (value == "OK") {
            sendBLEMessage("Please type WiFi SSID (WiFi name)?");
            setupStep = 1;
            Serial.println("Received OK, asking for SSID");
          }
          break;

        case 1:
          wifi_name = value;
          char messageBuffer[100];
          snprintf(messageBuffer, sizeof(messageBuffer), "Great! Your WiFi name is: %s", wifi_name.c_str());
          sendBLEMessage(messageBuffer);
          delay(4000);
          sendBLEMessage("Please type your WiFi password?");
          setupStep = 2;
          Serial.println("Received SSID: " + wifi_name);
          break;

        case 2:
          wifi_pass = value;
          sendBLEMessage("Great! WiFi password was successfully received. I have all the Info that I need.");
          delay(4000);
          sendBLEMessage("Please wait a moment while we try to connect to WiFi.");

          Serial.println("Received password, attempting WiFi connection");

          WiFi.begin(wifi_name.c_str(), wifi_pass.c_str());
          int tries = 0;
          const int maxTries = 3;
          while (WiFi.status() != WL_CONNECTED && tries < maxTries) {
            delay(2000);
            tries++;
            Serial.print("WiFi connection attempt ");
            Serial.print(tries);
            Serial.println(" of " + String(maxTries) + " failed, retrying");
            sendBLEMessage("Connecting to WiFi was not successful. I will try again!");
          }

          if (WiFi.status() == WL_CONNECTED) {
            sendBLEMessage("Connecting to WiFi was successful! You can disconnect me from Bluetooth!");
            setupStep = 3;
            Serial.println("WiFi connected successfully");
          } else {
            sendBLEMessage("Connecting to WiFi was not successful after all attempts. Try to reconnect the phone with GreenWateringIRI25 device and send WiFi credentials again!");
            setupStep = 0;
            Serial.println("WiFi connection failed after all attempts");
          }
          break;
      }
    }
};

unsigned long CharacteristicCallbacks::messageStartTime = 0;

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");

  BLEDevice::init("GreenWateringIRI25");
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new ServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ |
                      BLECharacteristic::PROPERTY_WRITE |
                      BLECharacteristic::PROPERTY_NOTIFY
                    );
  pCharacteristic->setCallbacks(new CharacteristicCallbacks());

  pCharacteristic->addDescriptor(new BLE2902());//add

  pService->start();
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  BLEDevice::startAdvertising();
  Serial.println("BLE setup complete, waiting for connections...");
}

void loop() {
  delay(50);
}