Bluetooth Low Energy (BLE) has a known limit of 20Bytes on the length of strings sent. There are ways of overriding this limit.
Hardware
In this tutorial, we’ll send data from an Android application, developed under React Native, to an ESP32. The methods described may be valid for other devices.
- Android device
- ESP32 BLE
BLE 20-byte limit
The application developed under React Native is fully capable of sending long character strings in the form of 20byte packets by default. Without modifying the previous tutorial, here’s the value received on the ESP32 side. Only the last packet is stored in memory.
01:48:39.734 -> ESP32BLE server ready 01:48:40.493 -> Server address:3c:61:05:31:5f:12 01:48:41.672 -> Client connected 01:48:48.169 -> Charac value: Helloworldthisisalon 01:48:48.253 -> Charac value: gstringletseewhatcom 01:48:48.374 -> Charac value: esout; 01:48:48.374 -> this is the last packet
Summary of methods for sending long strings via BLE
- Recover multiple packets (receiver side)
- Send the long chain in small packets (sender side)
- Increase MTU limit from 23 bytes to 512 bytes
Recover multiple packages
If the device sending the messages is capable of handling the sending of strings that exceed the MTU limit, as is the case in our example, all that remains is to configure the receiving module to concatenate the various packets received. To do this, we use an end-of-string character, such as “;”.
In the onWrite function of the ESP32BLE module, we add an end-of-string test and a longMsg variable to act as a buffer.
std::string longMsg; class MyCallbacks: public BLECharacteristicCallbacks { void onWrite(BLECharacteristic *pCharacteristic) { std::string value = pCharacteristic->getValue(); if (value.length() > 0) { Serial.print("Charac value: "); for (int i = 0; i < value.length(); i++) Serial.print(value[i]); Serial.println(); if(value.find(";") != -1){ //Serial.println("this is the last packet"); longMsg = longMsg + value; Serial.print("longMsg: "); for (int i = 0; i < longMsg.length(); i++) Serial.print(longMsg[i]); Serial.println(); //do whatever you want with longMsg then erase longMsg = ""; }else{ longMsg = longMsg + value; } } } };
Send packets of predefined size
If the device sending the data doesn’t handle messages larger than the MTU, then the string can be split into packets of predefined size (chunksize). This method makes it possible to control the size of packets sent.
In the React Native project, we’re creating a function that will transform the long string into an array of bytes, which we’ll send in packets.
const sendLongMessage = async (data: string, chunksize: number) => { console.log("data : ",data) var bytes = convertStringToByteArray(data) var times = Math.ceil(bytes.length/chunksize); var packets = []; console.log("split data ",times," times"); //console.log("bytes: ",bytes) var i=0 for(var time=0;time<times;time++){ var packet = bytes.slice(time*chunksize, (time+1)*chunksize) packets.push(packet) console.log(time," : ",byteArrayToString(packet)) sendMessage(byteArrayToString(packet)); await delay(100); } }
N.B.: a delay function can be introduced to allow time for the message to be sent. delay(100)
const delay = (ms: number) => new Promise( resolve => setTimeout(resolve, ms) );
Increase application MTU limit
By default, the react-native-ble-manager library sends 20-byte packets. There is a method for specifying the Maximum Transmission Unit (MTU) size to the BLE module.
In the application code, during connection, before retrieving services, add an MTU request
BleManager.requestMTU(device.id, 512).then( (mtu) => { setMTU(mtu); } ) //request the MTU size in bytes
When sending the message, you can specify the maximum message size in bytes, “mtu”, in the BLEManager.write() function.
BleManager.write( selectedDevice.id, serviceid, caracid, buffer.toJSON().data, mtu // or 512 ).then(() => { // Success code console.log("Write: " + buffer.toJSON().data); })
On the ESP32 side, the BLEDevice library provides a method for defining the MTU size.
BLEDevice::setMTU(512); //between 23 and 517 (bluetooth 4.2)
N.B.: In this example (Android+ESP32), the only way to increase the limit is to set the maximum number of bytes in the BLEManager.write() function. We’ll leave the other information that might be useful for another configuration (iOS, HM10, etc.).
Once the code has been modified, when we return the same character string, we receive its full value in the BLE feature
Applications
- Increase the size of messages sent to the BLE module
- Imitate Bluetooth classic operation on the fly