/*  Test d'envoi de mesures par notifications Bluetooth BLE à partir d'un ESP32    YLC 10/01/2021
   D'après l'exemple de Neil Kolban. Version ESP32 par Evandro Copercini. MàJ par chegewara.
   Serveur BLE qui envoie par notification périodique des valeurs en provenance de divers capteurs.
   Ici les capteurs sont simulés par des tirages aléatoires.
   Processus : la création d'un serveur BLE se compose des étapes suivantes :
         1. création du serveur BLE
         2. création d'un service BLE
         3. création d'une caractéristique BLE pour ce service
         4. création d'un descripteur BLE pour cette caractéristique
         5. Démarrage du service.
         6. Démarrage de l'annoncage (advertising)
         7. Boucle de notifications.
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>          // descripteur BLE pour les notifications sur ESP32

BLEServer *pServer = NULL;     // definir Bluetooth en tant que serveur 
BLECharacteristic* pCharacteristic1 = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t tablevaleurs[8];   // Notifier simultanément jusqu'à 8 valeurs (choix arbitraire) comprises entre 0 et 255.
                           // ATTENTION: on ne peut pas envoyer par notification plus de 20 octets simultanément.
// Voir ce site pour générer des identifiants perso:  https://www.uuidgenerator.net/
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"   // Identifiant du service
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"   // Identifiant de la caractéristique

//  fonctions de rappel sur les évènement de connexion et déconnexion
class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };
    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};
// - - - - - - - - - - - - - - - - - - - - - -
void setup() {
  Serial.begin(115200);

  BLEDevice::init("ESP32");           // Initialisation du dispositif utilisé : ESP32)

  pServer = BLEDevice::createServer();                  // Création du serveur BLE
  pServer->setCallbacks(new MyServerCallbacks());

  BLEService *pService = pServer->createService(SERVICE_UUID);     // Création d'un service BLE

  pCharacteristic1 = pService->createCharacteristic(        // Création d'une caractéristique BLE pour ce service
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );
  
  pCharacteristic1->addDescriptor(new BLE2902());    // Création d'un descripteur BLE pour cette caractéristique

  pService->start();                        // Démarrage du service

  // Démarrage de l'annoncage         
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);   // valeur  0x00 pour ne pas annoncer ce paramètre
  BLEDevice::startAdvertising();             // Annonce qu'une connexion d'un client est possible
  Serial.println("Attente de la connexion d'un client");
}

// - - - - - - - - - - - - - - - - - - - - - -
void loop() {
  // notification des données vers le client :
  if (deviceConnected) {            // si connexion établie avec le client
    // on simule des valeurs de 4 capteurs par des tirages aléatoires
    tablevaleurs[0] = random(0,255);
    tablevaleurs[1] = random(0,255);
    tablevaleurs[2] = random(0,255);
    tablevaleurs[3] = random(0,255);            
    pCharacteristic1->setValue(tablevaleurs, 8);     // choix arbitraire de 8 valeurs possibles
    pCharacteristic1->notify();                                   // notification (envoi des données)
    delay(200);                 // ralentir l'envoi des données pour ne pas saturer la pile bluetooth
  }
  // Déconnexion du client :
  if (!deviceConnected && oldDeviceConnected) {    // si changement de client
    delay(500);                                                                 // attendre que la pile bluetooth soit prête
    pServer->startAdvertising();                                     // relancer l'annoncage
    Serial.println("Déconnexion du client : relance de l'annoncage");
    oldDeviceConnected = deviceConnected;
  }
  // Connexion du client :
  if (deviceConnected && !oldDeviceConnected) {     // nouvelle connexion du client
    Serial.println("Connexion du client");
    oldDeviceConnected = deviceConnected;
  }
}