Réception BLE Simple WINDEV Mobile & ESP32

J’ai passé un peu de temps à chercher comment utiliser la connexion BLE, réduite à sa plus simple expression entre une application Android sous Windev et un ESP 32.

Le principe est simple coté ESP32, on déclare le nom de l’équipement BLE et les UUIDs.
Dans mon cas :

  • TEST-UART pour le nom
  • SERVICE_UART_UUID « 6E400001-B5A3-F393-E0A9-E50E24DCCA9E »
  • CHARACTERISTIC_UUID_RX « 6E400002-B5A3-F393-E0A9-E50E24DCCA9E »
  • CHARACTERISTIC_UUID_TX « 6E400003-B5A3-F393-E0A9-E50E24DCCA9E »

Le 1er UUID est le service, c’est là que l’on défini les caractéristiques que nous souhaitons.
On peut dire que c’est le point d’entrée de nos données.

Le 2eme et le 3eme parlent d’eux même.  Je ne me suis attardé que sur le RX, le TX viendra plus tard, mais il reste beaucoup plus simple.
Pour générer un UUID* vous pouvez le faire là : https://www.uuidgenerator.net/

*Pour ceux qui se demande ce qu’est un UUID, c’est simplement un IDentifiant Unique Universelle codé sur 128bits affiché en hexadécimal. Comme ça, quand vous créez un objet BLE, ses identifiants étant unique, il ne devrait être que celui que vous avez créer.

 

Ce qui m’a dérouté avant tout, c’est la terminologie. En gros pour obtenir une valeur qui provient d’un périphérique BLE, on crée une notification (notify) et on s’y abonne pour avoir sa valeur.
C’est aussi simple que ça !

Voila le code qui en est ressorti.
Coté ESP32 il y a le code de l’émission/réception

ESP32
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

//
// Les UUID sont unique pour vous, vous pouvez en générer pour chaque application
//

#define SERVICE_UART_UUID      "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

BLEServer* pServer = NULL;
BLECharacteristic* pTxCharacteristic = NULL;
BLECharacteristic* pRxCharacteristic = NULL;

bool estConnecte = false;
bool etaitConnecte = false;


class EtatServeur : public BLEServerCallbacks
{
void onConnect(BLEServer* pServer)
{
estConnecte = true;
}

void onDisconnect(BLEServer* pServer)
{
estConnecte = false;
}
};

class CharacteristicUART : public BLECharacteristicCallbacks
{
void onWrite(BLECharacteristic* pCharacteristique)
{
std::string rxValue = pCharacteristique->getValue();

if (rxValue.length() > 0)
{
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i]);
Serial.println();
Serial.println("*********");
}
}
};


void setup() {
Serial.begin(115200);

// Create the BLE Device
BLEDevice::init("TEST-UART");

//BLEDevice::getAddress(); // pour récupere la MAC adresse de votre BLE
pServer = BLEDevice::createServer();
pServer->setCallbacks(new EtatServeur());

BLEService* pServiceUART = pServer->createService(SERVICE_UART_UUID);
pTxCharacteristic = pServiceUART->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
// Create a BLE Descriptor : Client Characteristic Configuration (for indications/notifications)
pTxCharacteristic->addDescriptor(new BLE2902());
pRxCharacteristic = pServiceUART->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
pRxCharacteristic->setCallbacks(new CharacteristicUART());

pServiceUART->start();

pServer->getAdvertising()->start();
Serial.println("UART Over BLE start advertising");

Serial.println("UART Over BLE wait connection");
}

void loop() {
String newValue = "";
bool fini = false;

//Si connecté envoie en permanance newValue, mais il peux être envoyé qu'a chaque 
// chaque modification de valeur, a vous de coder dans ce sens
if (estConnecte)
{
// envoie 
newValue = "TEXT ENVOYER";

pTxCharacteristic->setValue(newValue.c_str());
pTxCharacteristic->notify();
delay(10); // bluetooth stack will go into congestion, if too many packets are sent

}

// déconnecté ?
if (!estConnecte && etaitConnecte)
{
Serial.println("UART Over BLE deconnection");
delay(500); // give the bluetooth stack the chance to get things ready      
pServer->startAdvertising(); // restart advertising
Serial.println("UART Over BLE restart advertising");
etaitConnecte = estConnecte;
}

// connecté ?
if (estConnecte && !etaitConnecte)
{
Serial.println("UART Over BLE connection");
etaitConnecte = estConnecte;

}
}

Coté WINDEV il n’y a que la réception.

WINDEV MOBILE
BTLEListePériphérique(detectUART)


PROCÉDURE INTERNE detectUART(BLE est un btlePériphérique)
crtq est une btleCaractéristique
SI BLE.Nom = "TEST-UART"
// On vérifie si on n'a pas déjà ajouté ce périphérique

// On vérifie la connexion n'a pas déjà été effectuée
SI BTLEEtatConnexion(BLE) <> btleEtatConnecté ALORS
LIB_UART = ""

// Lancement de la connexion
SI BTLEConnecte(BLE) ALORS
crtq = BTLERécupèreUneCaractéristique(BTLERécupèreUnService(BLE,"6E400001-B5A3-F393-E0A9-E50E24DCCA9E"),"6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
BTLECaractéristiqueChangementValeur(crtq,showUART)
ToastAffiche("Connexion UART OK",toastLong)
RENVOYER Faux
FIN
FIN
FIN
FIN

PROCÉDURE INTERNE showUART(caractéristique est une btleCaractéristique <utile>, bufValeur est un Buffer)
sBuf est une chaîne ANSI = bufValeur
LIB_UART = sBuf
FIN

J’espère que ça servira de base à certain qui, comme moi, ont galéré.

C’est simple non?

3 Comments

  1. Bonjour,

    Tout d’abord, merci pour le code ci dessus.
    j’ai un projet ou je souhaite utilisé 8 esp32 qui puisse communiquer de façon bidirectionnelle avec une application windev mobile. il y aura 2 capteurs par esp32 est 2 leds pour le retour d’information. les capteur doivent remonté l’information a l’application et en retour l’application envoie l’information d’allumage d’une led.
    j’ai regarder pour lister les ESP32 dans une zone répétée et les connecter avec un bouton, je pence que je vais devoir déclaré une variable par ESP32.
    pourrai tu m’aider pour la réception multiple et la transmission?
    Par avance merci

    • Bonjour,
      Je pense effectivement qu’il faudra déclarer une variable correspondant à chaque ESP32 pour y accéder.
      Je ne connais pas ton application, mais parfois une liaison wifi peut être plus simple, dans mon cas, je ne pouvais pas.
      Désolé, je ne pourrai pas t’aider, ayant de mon coté une charge de travail ne me le permettant pas.
      Bon courage.
      Amicalement.

  2. Bonjour STEPH

    Bien qu il s agisse d’un ancien post
    Je me suis inspiré de votre code réception. Pour ma part je pilote un cadenas connecte , avec exactement le même service et caractéristique 6e400003 pour la notification.
    J ai au préalable validé la notification client , en écrivant sur le descripteur de la 6e400003 0x01,0x00. J
    J ai bien mis 2 procédures internes
    Et un appel a la première
    Je n obtiens rien , a un moment oui c’est venu mais je n ai pas pu reproduire depuis avec tous les tests dans tous les sens j ai perdu le fil …

    //ci dessous le code
    Changedevaleur() //apres etre connecte et avoir lance ma requete pour connaitre niveau batterie

    PROCÉDURE INTERNE Changedevaleur()
    caracteristiqueencours=TABLEAUCARACTERISTIQUES[2]
    ToastAffiche( » Traitement niveau Batterie… »,toastCourt,cvBas,chCentre)
    BTLECaractéristiqueChangementValeur(caracteristiqueencours, Litlevelbatterie)
    RENVOYER Faux
    FIN

    PROCÉDURE INTERNE Litlevelbatterie(caracteristique_level est une btleCaractéristique , bufvaleur est un Buffer)

    ToastAffiche(caracteristique_level..UUID,toastLong,cvBas,chCentre)
    sbuf est une chaîne ANSI
    sbuf=BufferVersHexa(bufvaleur)
    ToastAffiche(« Level= »+sbuf,toastLong,cvBas,chCentre)
    Multitâche(-10)
    SI sbuf » » ALORS
    resultatbatterie=Vrai
    FIN
    FIN
    //

    ***Question si vous le permettez **
    Ce qui me dérange , la procédure Changedevaleur() est appelé qu une seule fois n’est ce pas ?
    elle déclenche donc l’écoute du changement de valeur de la caractéristique en gros on attend une trame a en réponse à la requête de demande de niveau de batterie . Mais si la trame n est pas prête lors de l’exécution de cette fonction est ce la raison pour laquelle je n’ai rien. Car cette procedure changevaleur() c’est un appel callback cela signifie qu il va etre répété autant de fois jusqu ‘à obtention d’une réponse ou bien ce n est pas le cas ?

    En résumé je ne pense pas être loin résultat car j ai obtenu quelque chose par hasard

    Je vous remercie si vous pouvez m’éclairer

    RIAD

Poster un Commentaire

Votre adresse de messagerie ne sera pas publiée.


*





Enter Captcha Here :