fbpixel
Étiquettes : , , ,

Le Bluetooth Low Energy (BLE) a une limitation connue d’une 20Bytes pour la longueur des chaînes envoyées. Ils existent des méthodes pour outrepasser cette limite.

Matériel

Dans ce tutoriel, nous envoyons des données à partir d’une application Android, développée sous React Native, vers une ESP32. Les méthodes décrites peuvent être valables avec d’autres appareils.

  • Appareil Android
  • ESP32 BLE

Limitation de 20 bytes du BLE

L’application développée sous React Native est tout à fait capable d’envoyer de longues chaînes de caractères sous forme de paquet de 20bytes par défaut. Sans modification du tutoriel précédent voici la valeur reçue côté ESP32. Seul le dernier paquet est gardé en mémoire.

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

Résumé des méthodes pour envoyer de longues chaînes via BLE

  • Récupérer plusieurs paquets (côté récepteur)
  • Envoyer la longue chaîne sous forme de petits paquets (côté émetteur)
  • Augmenter la limite MTU de 23 bytes à 512 bytes

Récupérer plusieurs paquets

Si l’appareil qui envoie les messages est capable de gérer l’envoie de chaine de caractères qui dépassent la limite MTU, comme c’est le cas dans notre exemple, il ne reste plus qu’à configurer le module récepteur pour concaténer les différents paquets reçus. Pour cela, nous utilisons un caractères de fin de chaîne, par exemple « ; ».

Dans la fonction onWrite de la caractéristique du module ESP32BLE, nous ajoutons un test de fin de chaîne et une variable longMsg qui nous servira de tampon.

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;
        }
      }
    }
};
esp32-ble-long-string-receive-packets Envoyer de longues chaînes de caractères via BLE

Envoyer des paquets de taille prédéfinie

Si l’appareil qui envoie les données ne gère pas les messages de taille supérieure au MTU, alors il est possible de séparer la chaîne de caractères en paquets de taille prédéfinie (chunksize). Cette méthode permet de maitriser la taille des paquets envoyés.

Dans le projet React Native, nous créons une fonction qui va transformer la longue chaîne de caractère en Array de bytes que nous allons envoyez par paquets.

    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);
        }
    }
esp32-ble-long-string-custom-size-packets Envoyer de longues chaînes de caractères via BLE

N.B.: une fonction de retard peut être introduite pour laisser le temps au message d’être envoyé. delay(100)

const delay = (ms: number) => new Promise(
  resolve => setTimeout(resolve, ms)
);

Augmenter la limite MTU de l’application

Par défaut, la librairie react-native-ble-manager envoie des paquets de 20bytes, Il existe une méthode permettant de spécifier au module BLE de modifier la taille du Maximum Transmission Unit (MTU)

Dans le code de l’application, pendant la connexion, avant de récupérer les services, ajouter une requête MTU

BleManager.requestMTU(device.id, 512).then(
        (mtu) => {
          setMTU(mtu);
        }
      ) //request the MTU size in bytes

Lors de l’envoie du message, vous pouvez spécifier la taille maximum du message en bytes, « mtu », dans la fonction BLEManager.write()

     BleManager.write(
       selectedDevice.id,
       serviceid,
       caracid,
       buffer.toJSON().data,
       mtu // or 512
     ).then(() => {
       // Success code
       console.log("Write: " + buffer.toJSON().data);
     })

Côté ESP32, il existe une méthode de la librairie BLEDevice permettant de définir la taille du MTU.

BLEDevice::setMTU(512); //between 23 and 517 (bluetooth 4.2)

N.B.: Dans cet exemple (Android+ESP32), seule la définition du nombre maximum de bytes dans la fonction BLEManager.write() permet d’augmenter la limite. Nous laissons les autres infos qui pourraient être utiles pour une autre configuration (iOS, HM10, etc.)

Une fois le code modifié, lorsqu’on renvoie la même chaîne de caractère, on reçoit la totalité de sa valeur dans la caractéristiques BLE

esp32-ble-long-string-increase-mtu Envoyer de longues chaînes de caractères via BLE

Applications

  • Augmenter la taille des messages envoyés au module BLE
  • Imiter le fonctionnement du Bluetooth classic de manière ponctuelle

Sources