L’interface BLUETOOTH du déclencheur de relais ( 2 de 2 )

Abordons maintenant la programmation du ESP32.

C’est pratiquement le même programme que l’interface Web, mais la partie Web est remplacée par la partie BLUETOOTH.

Fonctions de la DEL

Une DEL RGB est utilisée pour afficher 2 conditions

  • Vert       : Le circuit est fonctionnel
  • Orange : Le voltage de la source d’alimentation est sous un certain seuil. La DEL clignote entre Orange et Vert

Afin d’ajuster au besoin l’intensité et la couleur de la DEL, le programme fait appel une fonction  (ledcWrite)  qui module la sortie PWM des broches selon la valeur fournie à la fonction

EEPROM

Les données importantes à conserver, même lors de mise hors tension, sont enregistrées dans la mémoire flash EEPROM. L’enregistrement s’exécute lors du changement d’une donnée.

Mesure de voltages

Le voltage de la source d’alimentation est surveillé. La donnée est envoyée à l’interface utilisateur lors d’une requête du client. Une DEL clignote en orange pour indiquer que le voltage est sous le seuil établi.

Les interruptions

L’état du laser et de l’interrupteur sont surveillés dans la partie «LOOP». Le programme exécute les instructions en série, une après l’autre en bouclage. L’état du laser ou de l’interrupteur n’est donc pas traité dès qu’il y a un changement, mais seulement quand le programme arrive aux instructions qui s’y rapporte. Pour traiter le plus rapidement possible le changement d’état, le mieux, c’est d’interrompre l’exécution du programme en cours et de prendre en considération immédiatement le changement d’état. C’est le rôle des fonctions d’interruptions.

Dès qu’une interruption est détectée par le processeur, celui-ci sauve son état d’exécution, exécute une portion de code liée à l’interruption (Interrupt Service Routine ISR), et revient ensuite à son état avant l’interruption pour continuer ce qu’il faisait.

Attention, à l’intérieur de la routine d’interruption, certaines fonctions sont inutilisables (delay ne fonctionne pas, millis renverra toujours la même valeur, les données séries reçues seront perdues et les signaux PWM sont affectés).

Toute valeur modifiée à l’intérieur de la routine d’interruption devra passer par une variable déclarée comme volatile, afin que le processeur aille chercher la valeur en mémoire et ne se fie pas à ce qui se trouve dans ses registres qui sont gelés au moment de l’interruption.

Le programme de déclencheur de relais est modifié pour traiter le plus rapidement possible la coupure du faisceau laser.

Fonction «attachInterrupt»

Pour définir une interruption, on se sert de la fonction attachInterrupt () , qui accepte comme arguments: la broche GPIO, le nom de la fonction à exécuter (Interrupt Service Routine ISR) et le mode

attachInterrupt(digitalPinToInterrupt(PIN_DETECTEUR_LASER_1), demande_oper_relais, FALLING);

Si un changement de l’état HAUT à l’état BAS (FALLING) se produit sur l’entrée GPIO 17 (PIN_DETECTEUR_LASER_1) , une interruption est générée. La fonction «demande_oper_relais» est exécutée. État HAUT : Faisceau présent sur le détecteur. État BAS : Faisceau absent sur le détecteur.

demande_oper_relais

void demande_oper_relais(){
blJetonOperRelais = 1;
}

On ne peut directement opérer le relais et tenir compte des délais configurés, les délais étant bloqués dans la routine de service d’interruption. Ici le programme met à 1 le jeton blJetonOperRelais et retourne la main à LOOP.

La boucle est divisée en partie, une partie ne peut commencer à s’exécuter que si le jeton est à 0.

if (!blJetonOperRelais) {
// * Traite les échanges sur BLUETOOTH ***
do_Uart_Tick();
}

Suite à l’interruption, le jeton étant à 1, le microcontrôleur va plus rapidement aux instructions associées changement d’état du GPIO qui a activé l’interruption. Ces instructions sont dans la boucle et s’exécutent si le jeton est à 1. Après exécution le jeton est remis à 0.


Instructions dans la boucle qui s’exécutent si le jeton est à 1
 

   if (blJetonOperRelais) {
        oper_delai_plus_relais();
        blJetonOperRelais = 0;
     } 

Fonctions

void oper_delai_plus_relais(){
    delaiDeReaction();
    declencheRelais();  // inclus le délai de retour 
 }
//***  Attente selon le délai de réaction ****
 void delaiDeReaction(){
   // Les «Serial.print» sont là pour le développement
   // En fonctionnement normal vaut mieux les mettre en 
   // commentaire. Ils influencent le temps d'exécution
   // des routines et faussent les délais programmés
   // Serial.println("Délai de réaction amorcé");
   if (blUnitDlReactMicroScd){
     delayMicroseconds(u32DelaiDeReaction);   // délai avant d'activer
                                              // le relais (en microseconde)
   }
   else {
     delay(u32DelaiDeReaction);               // délai avant d'activer
                                              // le relais (en milliseconde)
   } 
 }
//   Activation du relais **
 void declencheRelais(){
   Serial.println("Déclenchement du relais amorcé");
   digitalWrite(PIN_ACTIVE_RELAIS, HIGH);     // Déclenche le relais
   delay(u32TempsRelaisActif);                // Attente en milliseconde 
   digitalWrite(PIN_ACTIVE_RELAIS, LOW);      // Relâche le relais
   Serial.println("Délai avant retour amorcé");
   delay(u32DelaiAvantRetour);                // Attente en milliseconde  
   Serial.println("Processus déclenchement du relais terminé"); 
   Serial.println("");                  
 }

L’APPLICATION


L’application est divisée en deux fichiers. Ils doivent être placés dans le même répertoire nommé «Declencheur_de_relais_Comm_Bluetooth_01»

Téléchargement

https://github.com/rcepmorel/Declencheur_de_relais_Comm_Bluetooth_01

Declencheur_de_relais_Comm_Bluetooth_01.ino

/*  DÉCLENCHEUR DE RELAIS COMMUNICATION BLUETOOTH
* 
* Auteur : Richard Morel
*     2018-12-17
* 
* Modification
*
*     
*/

// ----------------------------------------------------------------------------- 
//             Importation des fichiers et définition des variables
// ----------------------------------------------------------------------------- 

//******* Affichage DEL ********
// Afin d'ajuster au besoin l'intensité et la couleur de la DEL, le programme
// fait appel une fonction (ledcWrite) qui module la sortie PWM des broches
// selon la valeur fournie à la fonction
#define LEDC_CHANNEL_0_VERT     0
#define LEDC_CHANNEL_1_ROUGE    1

// utiliser une précision de 13 bits pour le temporisateur LEDC
#define LEDC_TIMER_13_BIT  13

// utilise 5000 Hz comme fréquence de base du LEDC
#define LEDC_BASE_FREQ     5000

#define DELROUGE  25 // DEL rouge reliée au GPIO25
#define DELVERTE  33 // DEL verte reliée au GPIO33

byte byBrightnessVert;
byte byBrightnessRouge;

//******* Convertisseurs Analogique/Numérique ******
#include <driver/adc.h>   
//ADC1_CHANNEL_7 D35 35

//*******   EEPROM   *****************
// Inclure la librairie de lecture et d'écriture de la mémoire flash
#include "EEPROM.h"

// définie le nombre de Bytes que l'on veut accéder
#define EEPROM_SIZE 64

//******  Bluetooth *********************
#include "BluetoothSerial.h"
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth est non actif
#endif
BluetoothSerial SerialBT;

#define MAX_PACKETSIZE 32   //Tampon de réception en série
char buffUART[MAX_PACKETSIZE];
unsigned int buffUARTIndex = 0;
unsigned long preUARTTick  = 0;

// ***** Mesure de voltage ************  
float flCalibrationDiviseurTsn = 8.02/7.97; // Valeur réelle diviser par
                                            // flVoltMesure lorsque 
                                            // flCalibrationDiviseurTsn
                                            // égal à 1

int inSeuilDeVoltage = 7;              // Niveau d'alerte de basse tension 
                                       // de l'alimentation d'entrée

float flReading;
float flVoltAlimCtrlReduit;
float flVoltMesure;


//*****  Interupteurs, détecteurs et sorties ******** 
#define PIN_ACTIVE_RELAIS      32      // Sortie pour déclencher le relais
#define PIN_DETECTEUR_LASER_1  13      // Détecte une MALT à l'entrée D13

#define PIN_BOUTON_DECLENCHEUR 26      // Détecte une MALT à l'entrée D26

volatile boolean blJetonOperRelais = 0;  
boolean blEtatBtnDeclencheur; 
boolean blTamponEtatBouton         = 1;
boolean blDeclencheRelais          = 0;
boolean blUnitDlReactMicroScd      = 0; // Unité du délai de réaction 
                                        // 1 => microseconde
                                        // 0 => milliseconde

// La variable suivante est de type «uint64_t» car le temps, 
// mesuré en millisecondes, deviendra rapidement un nombre grand
uint64_t u64HorodatageBtnDeclencheur = 0;  // La dernière fois que la broche
                                           // de sortie a été basculée
                                         
uint32_t u32DelaiReActInterup = 3000;  // Délai de réactivation
                                       // Pas plus d'un changement d'état 
                                       // au 3 secondes pour éliminer
                                       // les intermittences    
                                   

uint64_t u64HorodatageRayonCoupe = 0;  // La dernière fois que le rayon
                                       // laser a été coupé
uint32_t u32DelaiReActRayon = 3000;    // Pas plus d'un changement d'état 
                                       // au 3 secondes pour éliminer
                                       // les intermittences    

// Les prochaines variables sont de type «unsigned int»
// Ceci évite des valeurs négatives lors de la première lecture du EEPROM
// au SETUP avant qu'il y est eu une première écriture
// Sinon, il pourrait y avoir blocage du programme
// Ces données sont aléatoires avant la première écriture                                
uint32_t u32DelaiDeReaction  = 0;      // Durée d'attente avant d'activer le relais
uint32_t u32TempsRelaisActif = 2000;   // Durée d'activation du relais en milliseconde
uint32_t u32DelaiAvantRetour = 1000;   // Délai en milliseconde avant de redonner
                                       // la main à la suite du programme après
                                       // l'activation du relais


//******** Divers ***************
int inChronoDebutIndicModReseau = 0;   // Chrono Indique le mode réseau
int inChronoDebutIndicBattFbl   = 0;   // Chrono Indique batterie faible


// ------------------------------------------------------------------------------- 
// FONCTION  FONCTION   FONCTION    FONCTION    FONCTION    FONCTION    FONCTION
// ------------------------------------------------------------------------------- 

//*****  Activation de la DEL   *****************
void ledcAnalogWrite(uint8_t channel, uint32_t value, uint32_t valueMax = 255) {
  // calculate duty, 8191 from 2 ^ 13 - 1
  if (value > valueMax){value = valueMax;}
  uint32_t duty = (8191 / valueMax) * value;
  
  // write duty to LEDC
  ledcWrite(channel, duty);
}

//******  Enregistrement dans la mémoire flash *******
void memFlashDataUser(){
  EEPROM.writeInt(0,  u32DelaiDeReaction);
  EEPROM.writeInt(4,  u32TempsRelaisActif);
  EEPROM.writeInt(8,  u32DelaiAvantRetour);
  EEPROM.writeInt(12, blUnitDlReactMicroScd);
  EEPROM.commit();
  delay(100);
}

//***  Attente selon le délai de réaction ****
void delaiDeReaction(){
  // Les «Serial.print» sont là pour le développement
  // En fonctionnement normal vaut mieux les mettre en 
  // commentaire. Ils influencent le temps d'exécution
  // des routines et faussent les délais programmés
  // Serial.println("Délai de réaction amorcé");
  if (blUnitDlReactMicroScd){
    delayMicroseconds(u32DelaiDeReaction);   // délai avant d'activer
                                             // le relais (en microseconde)
  }
  else {
    delay(u32DelaiDeReaction);               // délai avant d'activer
                                             // le relais (en milliseconde)
  } 
}

//******   Activation du relais **************
void declencheRelais(){
  Serial.println("Déclenchement du relais amorcé");
  digitalWrite(PIN_ACTIVE_RELAIS, HIGH);     // Déclenche le relais
  delay(u32TempsRelaisActif);                // Attente en milliseconde 
  digitalWrite(PIN_ACTIVE_RELAIS, LOW);      // Relâche le relais
  Serial.println("Délai avant retour amorcé");
  delay(u32DelaiAvantRetour);                // Attente en milliseconde  
  Serial.println("Processus déclenchement du relais terminé"); 
  Serial.println("");                  
}

void oper_delai_plus_relais(){
   delaiDeReaction();
   declencheRelais();  // inclus le délai de retour 
}

void demande_oper_relais(){
  blJetonOperRelais = 1;
}
//*****  Choix d'affichage de la couleur de la DEL *******
//           AFFICHAGE VERT SEULEMENT
void AfficheVert(){
      byBrightnessVert  = 255;
      byBrightnessRouge = 0 ;
      ledcAnalogWrite(LEDC_CHANNEL_0_VERT, byBrightnessVert);
      ledcAnalogWrite(LEDC_CHANNEL_1_ROUGE,byBrightnessRouge);
}



 // *******  Traite les échanges sur BLUETOOTH ******** 
 #include "echange_Bluetooth_et_traitement.h"
 



// -------------------------------------------------------------------------------
// SETUP   SETUP   SETUP   SETUP   SETUP   SETUP   SETUP   SETUP   SETUP   SETUP
// ------------------------------------------------------------------------------- 
void setup() {
  Serial.begin(115200);
  Serial.println();


  //**********  EEPROM *************
  if (!EEPROM.begin(EEPROM_SIZE))
  {
    Serial.println("failed to initialise EEPROM"); delay(1000000);
  }
  
  Serial.println();
 
  //**********  ENTRÉES - SORTIES *************
  pinMode(PIN_ACTIVE_RELAIS, OUTPUT );
  digitalWrite(PIN_ACTIVE_RELAIS, LOW);

  pinMode(PIN_DETECTEUR_LASER_1, INPUT);
  pinMode(PIN_BOUTON_DECLENCHEUR, INPUT_PULLUP);   // active la résistance
                                                   // de pull-up interne sur le +3V

  // Un petit délai pour laisser les choses se stabiler
  delay(30);
  
  attachInterrupt(digitalPinToInterrupt(PIN_DETECTEUR_LASER_1), demande_oper_relais, FALLING);

  //**********  CONVERTISSEURS ANALOGIQUE/NUMÉRIQUE *************
  //     Configuration pour faire des mesures sur D35
  //     (voltage de la source d'alimentation) ******
  adc1_config_width(ADC_WIDTH_BIT_12);         // Définie la résolution (0 à 4095)
  adc1_config_channel_atten(ADC1_CHANNEL_7,    // Le voltage maximum au GPIO
                            ADC_ATTEN_DB_11);  // est de 3.3V



  // *********** BLUETOOTH ****************************
  // Ce Bluetooth n'est pas pris en charge pas IOS
  if(!SerialBT.begin("ESP32_DeclencheurDeRelais")){ //Bluetooth device name , NIP non disponible
    Serial.println("Erreur lors de l'initialisation du Bluetooth");
  }else{
    Serial.println("Bluetooth initialisé");
  } 


  //**********  DEL *************
  // Setup timer and attach timer to a led pin
  ledcSetup(LEDC_CHANNEL_0_VERT, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(DELVERTE, LEDC_CHANNEL_0_VERT);
  ledcSetup(LEDC_CHANNEL_1_ROUGE, LEDC_BASE_FREQ, LEDC_TIMER_13_BIT);
  ledcAttachPin(DELROUGE, LEDC_CHANNEL_1_ROUGE);

/*
  AfficheVert();
*/

  // Lecture des valeurs sauvegardées dans le EEPROM 
  u32DelaiDeReaction     = EEPROM.readInt(0);
  u32TempsRelaisActif    = EEPROM.readInt(4); 
  u32DelaiAvantRetour    = EEPROM.readInt(8);
  blUnitDlReactMicroScd  = EEPROM.readInt(12);  

  if (u32DelaiDeReaction == 4294967295){ // valeur par défaut du ESP
      u32DelaiDeReaction  = 0;           // Changer sinon le programme est figé  
      u32TempsRelaisActif = 1000;        // pour longtemps 
      u32DelaiAvantRetour = 0;
      
      memFlashDataUser();
      
      u32DelaiDeReaction     = EEPROM.readInt(0);  // Validation 
      u32TempsRelaisActif    = EEPROM.readInt(4); 
      u32DelaiAvantRetour    = EEPROM.readInt(8);
      blUnitDlReactMicroScd  = EEPROM.readInt(12);  
  }
  
  Serial.print(u32DelaiDeReaction);
  Serial.println(" delaiDeReaction " );

  Serial.print(u32TempsRelaisActif);
  Serial.println(" tempsRelaisActif " );

  Serial.print(u32DelaiAvantRetour);
  Serial.println(" delaiAvantRetour " );

  Serial.print(blUnitDlReactMicroScd);
  Serial.println(" Bool unité délai de réaction " );


  
  //***** Divers ******
  inChronoDebutIndicModReseau = millis();
  Serial.println("PRÊT");
}

// ------------------------------------------------------------------------------- 
// LOOP     LOOP     LOOP     LOOP     LOOP     LOOP     LOOP     LOOP     LOOP 
// ------------------------------------------------------------------------------- 
void loop() {  
  if (blJetonOperRelais) {
     oper_delai_plus_relais();
     blJetonOperRelais = 0;
  }

  if (!blJetonOperRelais) {
     //******* Lecture des entrées numériques  ******  

     blEtatBtnDeclencheur = digitalRead(PIN_BOUTON_DECLENCHEUR);
     if (blEtatBtnDeclencheur != blTamponEtatBouton){
        if ((millis() - u64HorodatageBtnDeclencheur) > u32DelaiReActInterup) {
           blTamponEtatBouton = blEtatBtnDeclencheur; // Mémorise le nouvel état
           u64HorodatageBtnDeclencheur = millis();
         }
     }
  }

  if (!blJetonOperRelais) {
     //***********  ACTIONS *****************
     if (!blTamponEtatBouton){;   // si l'état du bouton est 0
       delaiDeReaction();
       declencheRelais();  // inclus le délai de retour
       blTamponEtatBouton = 1;
     }
  }

  if (!blJetonOperRelais) {
     // ******* ********   Lecture du voltage d'alimentation   **********************
     //    
     // Méthode de G6EJD  (applicable si l'atténuation est 11dB
     // et la résolution est 12 bits)
     flReading = analogRead(35);
     flVoltAlimCtrlReduit = -0.000000000000016*pow(flReading,4)
                               +0.000000000118171*pow(flReading,3)
                               -0.000000301211691*pow(flReading,2)
                               +0.001109019271794*flReading+0.034143524634089;
     flVoltMesure = flVoltAlimCtrlReduit*122/22;        // Diviseur de tension
                                                        // 100K, 22K
     flVoltMesure = flVoltMesure*flCalibrationDiviseurTsn; // correction attribuable aux 
                                                        // valeurs imprécises du diviseur 
                                                        // de tension et au changement
                                                        // de ESP32

/* 
  Serial.print(flReading); Serial.print(" DigitalValueVoltAlimCtrl ");
  Serial.print(flVoltAlimCtrlReduit); Serial.print(" flVoltAlimCtrlReduit  ");
  Serial.print(flVoltMesure); Serial.println(" flVoltMesure"); 
  Serial.println(" "); 
*/

/* 
  Serial.print(blEtatLaser1); Serial.print(" État détecteur Laser,");
  Serial.print(blEtatBtnDeclencheur); Serial.print(" État Interrupteur,");
  Serial.print(flVoltMesure); Serial.println(" Voltage d'alimentation,");
*/
  }

  if (!blJetonOperRelais) {
     // *****************   Traitement de l'affichage de la DEL  ************************
     //     
     if (flVoltMesure > inSeuilDeVoltage ){          // Voltage d'alimentation > 7 volts 
        AfficheVert();
     }else{                                          // Voltage d'alimentation < 7 volts 
       if ((millis() - inChronoDebutIndicModReseau) > 1000){
          if (inChronoDebutIndicBattFbl == 0) {
             inChronoDebutIndicBattFbl= millis();    // Démarre le chrono Indique
                                                     // batterie faible
          }   
          if ((millis() - inChronoDebutIndicBattFbl) < 1000){ // DEL ORANGE pendant
                                                              // 1 seconde
             ledcAnalogWrite(LEDC_CHANNEL_0_VERT,   32);
             ledcAnalogWrite(LEDC_CHANNEL_1_ROUGE, 128);
          } 
          else{
             AfficheVert();                          // Vert OK
                                                     // 
             inChronoDebutIndicModReseau = millis(); // Démarre le chrono
                                                     // Indication le mode réseau
             inChronoDebutIndicBattFbl = 0;          // Remet à zéro le chrono
                                                     // Indication batterie faible
         }
       }
     }
  }

  if (!blJetonOperRelais) {
     // ***************   Traite les échanges sur BLUETOOTH   *****************
     do_Uart_Tick(); 
  }
} // # Fin du Void Loop


echange_Bluetooth_et_traitement.h

// ------------------------------------------------------------------------------- 
//            ÉCHANGE ET TRAITEMENT BLUETOOTH
// ------------------------------------------------------------------------------- 
//
//***** Renvoi des données du ESP32 vers le Client ****
// ****Trame de réponse : [ |DATA|#|#|#|#|#| ]  # est un nombre.
void envoieDataVersClient(){

      Serial.print(flVoltMesure);
      Serial.println(" flVoltMesure " );
      Serial.print(u32DelaiDeReaction);
      Serial.println(" delaiDeReaction " );
      Serial.print(u32TempsRelaisActif);
      Serial.println(" tempsRelaisActif " );
      Serial.print(u32DelaiAvantRetour);
      Serial.println(" delaiAvantRetour " );
      Serial.print(blUnitDlReactMicroScd);
      Serial.println(" Bool unité délai de réaction " );
      Serial.println();
      delay(0);
      int inPauseDeTransmission = 100;  // > 50 Temporisation pour éviter les engorgements 
      SerialBT.print("[ |");                 delay(inPauseDeTransmission);
      SerialBT.print("DATA|");               delay(inPauseDeTransmission);
      SerialBT.print(flVoltMesure);          delay(inPauseDeTransmission);
      SerialBT.print("|");                   delay(inPauseDeTransmission);
      SerialBT.print(u32DelaiDeReaction);    delay(inPauseDeTransmission);
      SerialBT.print("|");                   delay(inPauseDeTransmission);
      SerialBT.print(u32TempsRelaisActif);   delay(inPauseDeTransmission);
      SerialBT.print("|");                   delay(inPauseDeTransmission);
      SerialBT.print(u32DelaiAvantRetour);   delay(inPauseDeTransmission);
      SerialBT.print("|");                   delay(inPauseDeTransmission);
      SerialBT.print(blUnitDlReactMicroScd); delay(inPauseDeTransmission);
      SerialBT.print("| ]");
}


//*****  Réception et traitement des échanges sur BLUETOOTH
void do_Uart_Tick()
{
  char charUart_Data=0;
   
  if(SerialBT.available()) 
  {
    size_t len = SerialBT.available();  // size_t  integer non signé, 
                                        // len =  nombre de caractères à lire
    uint8_t u8SerialBuffer[len + 1];    // uint8_t integer non signé 8 bits,
                                        // équivaut à byte
    u8SerialBuffer[len] = 0x00;
    SerialBT.readBytes(u8SerialBuffer, len);
    memcpy(buffUART + buffUARTIndex, u8SerialBuffer, len);// s'assurer que le
                                                          // port série peut
                                                          // lire l'intégralité
                                                          // de la trame de données
    buffUARTIndex += len;
    preUARTTick = millis();
    if(buffUARTIndex >= MAX_PACKETSIZE - 1) 
    {
      buffUARTIndex = MAX_PACKETSIZE - 2;
      preUARTTick = preUARTTick - 200;
    }
  }
  if(buffUARTIndex > 0 && (millis() - preUARTTick >= 100))
  { //données prêtes
    buffUART[buffUARTIndex] = 0x00;
    if(buffUART[0]=='X')                    // Réserve
    {
    }

    //***********  Demande de déclenchement du relais ****
    else if (buffUART[0]=='C')   // CLIC,D           
    {
      Serial.print("Data brut du buffer de réception ->");
      Serial.println(buffUART);
      sscanf(buffUART,"CLIC,%s",&charUart_Data);
      Serial.print("Data après traitement ->"); 
      Serial.print(charUart_Data);
      Serial.println();
    }
    //***********  Démarrage, connexion Bluetooth réussie, envoie des données initiales ****
    //***********  Envoie des données du ESP32 vers le Client ****
    else if (buffUART[0]=='I')   // INIT,I           
    {
      Serial.print("Data brut du buffer de réception ->");
      Serial.println(buffUART);
      sscanf(buffUART,"INIT,%s",&charUart_Data);
      Serial.print("Data après traitement ->"); 
      Serial.print(charUart_Data);
      Serial.println();
    }
    else if (buffUART[0]=='M')   // Unité : délai de réaction = ms
    {
      charUart_Data='M';
      blUnitDlReactMicroScd = 0;
      Serial.print(blUnitDlReactMicroScd);
      Serial.println(" Milliseconde ");
      
    }
    //***** Réception des données venant de la TABLLETTE allant vers le ESP32  ****
    //      Nouveau DATA
    else if (buffUART[0]=='N') // Venant de l'action du bouton d'envoie
    {
      charUart_Data='N';
      Serial.print("Data brut du buffer de réception ->");
      Serial.println(buffUART);
      sscanf(buffUART,"NDATA,%i,%i,%i",&u32DelaiDeReaction,&u32TempsRelaisActif,&u32DelaiAvantRetour);
      Serial.print("Data après traitement ->");  
      Serial.print(u32DelaiDeReaction);
      Serial.print("/");
      Serial.print(u32TempsRelaisActif);
      Serial.print("/");
      Serial.println(u32DelaiAvantRetour);
      Serial.println();
    }
    else if (buffUART[0]=='U')   // Unité : délai de réaction = us
    {
      charUart_Data='U';
      blUnitDlReactMicroScd = 1;
      Serial.print(blUnitDlReactMicroScd);
      Serial.println(" Microseconde ");
    }
    else  charUart_Data=buffUART[0];
    buffUARTIndex = 0;
  }



  //****** EXÉCUTE LES DEMANDES ****
  //    
  switch (charUart_Data)    
    {    
      // ***** DÉCLENCHEMENT DU RELAIS ********
      case 'D':
      delaiDeReaction();
      declencheRelais();  // inclus le délai de retour
      break;
      
      // ***** Envoie des données du ESP32 vers le Client ********
      case 'I':
      envoieDataVersClient();
      break;
      
      case 'M':
      // Enregistrement des données dans le EEPROM
      memFlashDataUser();   
      //***** Renvoi des données du ESP32 vers le Client ****
      envoieDataVersClient();
      break;

      case 'N':
      // Enregistrement des données dans le EEPROM
      memFlashDataUser();  
      //***** Renvoi des données du ESP32 vers le Client ****
      envoieDataVersClient();
      break;

      case 'U':
      // Enregistrement des données dans le EEPROM
      memFlashDataUser();  
      //***** Renvoi des données du ESP32 vers le Client ****
      envoieDataVersClient();
      break;
      
      
      default:break;
    }
}




<- L’interface BLUETOOTH du déclencheur de relais ( 1 de 2 )         Déclencheur de relais – Interfaces Web et Bluetooth actives simultanément ->