ESP32 Web BLE : visualisation des données du capteur en direct (graphiques BME280)

ESP32 Web BLE : visualisation des données du capteur en direct (graphiques BME280)

Dans ce projet, nous allons vous montrer comment utiliser Web Bluetooth (Web BLE) avec l’ESP32 pour afficher les données du capteur en direct sur un navigateur pendant que vous êtes connecté à votre ESP32 via BLE. Web Bluetooth (Web BLE) vous permet de connecter et de contrôler des appareils compatibles BLE, comme l’ESP32, directement depuis votre navigateur Web à l’aide de JavaScript.

ESP32 Web BLE : graphiques de visualisation de données en direct

Web BLE n’est pris en charge que sur les appareils Android, les ordinateurs Windows et les ordinateurs Mac OS. Nous vous recommandons d’utiliser le navigateur Google Chrome. Il n’est pas pris en charge sous iOS, mais vous pouvez utiliser une application comme Bluefy pour émuler un navigateur Web BLE sur iOS (nous vous montrerons comment l’utiliser dans ce tutoriel).

Table des matières

Dans ce tutoriel, nous aborderons les sujets suivants :

Conditions préalables

Avant de poursuivre ce didacticiel, assurez-vous de respecter ces prérequis :

1. Préparation de l’IDE Arduino

Nous allons programmer l’ESP32 à l’aide de l’IDE Arduino. Assurez-vous que les cartes ESP32 sont installées avant de continuer. Suivez d’abord le tutoriel suivant, vous ne l’avez pas déjà fait :

Installation des bibliothèques

Pour ce tutoriel, nous utiliserons un capteur BME280 et la bibliothèque Adafruit_BME280. Installez-le avant de continuer.

Dans l’IDE Arduino, accédez à Sketch > Inclure la bibliothèque > Gérer les bibliothèques… et recherchez le nom de la bibliothèque : Adafruit BME280. Vous devez également installer la bibliothèque de capteurs unifiés Adafruit (une fenêtre contextuelle s’affiche pour l’installer si vous ne l’avez pas déjà fait)

Installation de la bibliothèque de capteurs Adafruit BME280 Arduino IDE

2. Pièces requises

Pour ce tutoriel, vous pouvez utiliser n’importe quel ESP32 de votre choix.

Carte ESP32 connectée à un capteur BME280

Pour le capteur, nous utiliserons un capteur BME280 qui enverra des mesures de température, d’humidité et de pression via BLE. Vous pouvez utiliser n’importe quel autre capteur avec seulement quelques modifications du code.

Vous pouvez utiliser les liens précédents ou vous rendre directement sur MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

1782433867 773 ESP32 Web BLE visualisation des donnees du capteur en direct

3. Schéma de circuit

Connectez un capteur BME280 à votre ESP32. Nous utilisons les GPIO 21 et 22 pour SDA et SCL. Vous pouvez choisir n’importe quel autre GPIO à condition de modifier le code en conséquence.

ESP32 avec schéma de câblage BME280

4. Installez l’application Bluefy (pour les appareils IOS)

L’API Web Bluetooth offre la possibilité de se connecter et d’interagir avec des périphériques Bluetooth Low Energy (comme l’ESP32). L’API est encore en développement, mais elle est généralement considérée comme stable et utilisable. Il a été implémenté dans Chrome, Edge, Opera (Android) et est pris en charge sur Android et Windows. Cependant, il n’est pas encore pris en charge sur iOS.

Vous pouvez vérifier la compatibilité du navigateur Web/appareil dans la documentation de l’API Web Bluetooth.

Si vous possédez un appareil iOS, vous pouvez toujours suivre ce projet en installant l’application Bluefy, qui est un navigateur BLE basé sur le Web. Voici le lien vers l’application :

Application Bluefy

Web BLE – Introduction rapide

Web Bluetooth (également parfois appelé Web BLE) est une technologie qui vous permet de connecter et de contrôler des appareils compatibles BLE, comme l’ESP32, directement depuis votre navigateur Web à l’aide de JavaScript.

Avec Web BLE, vous pouvez créer des applications Web qui interagissent avec vos appareils ESP32 via Bluetooth, vous permettant de contrôler les broches GPIO, d’échanger des données et de gérer vos appareils à distance via une interface Web (tout appareil prenant en charge un navigateur Web, comme votre ordinateur ou votre smartphone*).

Expliquer le Web Bluetooth avec ESP32

*sauf les appareils iOS. Alternativement, vous pouvez utiliser une application comme Bluefy – Web BLE Browser.

L’un des principaux avantages de Web Bluetooth est qu’il fonctionne sur différents appareils et systèmes d’exploitation via un navigateur Web compatible, sans qu’il soit nécessaire d’installer une application dédiée.

Cela signifie que vous pouvez utiliser un smartphone, une tablette ou un ordinateur de bureau pour connecter et contrôler les appareils ESP32 à l’aide d’une application Web BLE dans votre navigateur Web.

L’API Web Bluetooth est encore en développement, mais elle est généralement considérée comme stable et utilisable. Il a été implémenté dans Chrome, Edge, Opera et Firefox, et est pris en charge sur Android et Windows. Cependant, il n’est pas encore pris en charge sur iOS.

Ressources Web BLE et BLE

Si vous débutez avec Web BLE et BLE sur l’ESP32, nous vous recommandons de jeter un coup d’œil rapide aux didacticiels suivants pour vous familiariser avec les concepts de base de Bluetooth Low Energy.


Aperçu du projet

Avant de continuer, jetons un coup d’œil rapide aux fonctionnalités du projet que nous allons construire :

  • L’ESP32 agit comme un périphérique BLE, annonçant sa présence.
  • Votre navigateur Web agit comme un contrôleur BLE qui obtient les lectures des capteurs (lit les caractéristiques de l’ESP32).
Exemple de démonstration simple ESP32 Web BLE
  • La structure ESP32 GATT aura un service (service de détection environnementale : UUID 181A) avec trois caractéristiques (température : UUID 2A6E, humidité : UUID 2A6F et pression : UUID 2A6D).
ESP32 Service de détection environnementale GATT
  • L’ESP32 lit en permanence le capteur BME280 et écrit les nouvelles valeurs dans les caractéristiques de température, d’humidité et de pression.
  • Votre navigateur se connectera au périphérique Bluetooth ESP32 et recevra des notifications chaque fois qu’une valeur change sur les caractéristiques de l’ESP32.
  • Il lit ces caractéristiques et met à jour une page Web avec les données du capteur.
  • La page Web affiche les lectures actuelles sur les cartes et les dernières lectures des capteurs sur les graphiques.
Application Web BLE ESP32 - Afficher les données du capteur sur les graphiques de température et d'humidité
Application Web BLE ESP32 - Afficher les données du capteur sur les graphiques

Appareil ESP32 BLE – Code Arduino

Le code suivant transforme l’ESP32 en un appareil BLE doté du service de détection environnementale BLE et de trois caractéristiques : température, humidité et pression.

Téléchargez le code suivant sur votre tableau et cela fonctionnera immédiatement.

/*
  Rui Santos & Sara Santos - Raspberryme.com
  Complete project details at https://Raspberryme.com/esp32-web-ble-sensor-visualization/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// BME280 GPIOs
#define SDA_PIN 21
#define SCL_PIN 22

// BME280 
Adafruit_BME280 bme;

// BLE UUIDs 
// Environmental Sensing Service
#define SERVICE_UUID              "181A"
// Temperature
#define TEMP_CHARACTERISTIC_UUID  "2A6E"
// Humidity
#define HUM_CHARACTERISTIC_UUID   "2A6F"
// Pressure
#define PRESS_CHARACTERISTIC_UUID "2A6D"

// BLE variables
BLEServer*         pServer            = nullptr;
BLECharacteristic* pTempChar          = nullptr;
BLECharacteristic* pHumChar           = nullptr;
BLECharacteristic* pPressChar         = nullptr;
bool               deviceConnected    = false;
bool               oldDeviceConnected = false;

// Send a reading every 5 seconds
const unsigned long SAMPLE_INTERVAL_MS = 5000;
unsigned long lastSampleMs = 0;

// BLE server callbacks
class ServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) override {
    deviceConnected = true;
    Serial.println("BLE client connected.");
  }
  void onDisconnect(BLEServer* pServer) override {
    deviceConnected = false;
    Serial.println("BLE client disconnected.");
  }
};

// Format a float to one decimal place and set it on a BLE characteristic,
// then call notify() so connected clients receive it immediately
void notifyFloat(BLECharacteristic* pChar, float value) {
  char buf[16];
  snprintf(buf, sizeof(buf), "%.1f", value);
  pChar->setValue(buf);
  pChar->notify();
}

void setup() {
  Serial.begin(115200);
  Serial.println("\nESP32 BME280 BLE Server starting...");

  // Initialize BME280 Sensor
  Wire.begin(SDA_PIN, SCL_PIN);
  if (!bme.begin(0x76)) { 
    Serial.println("BME280 not found!");
    while(1); 
  }

  // ESP32 BLE init
  BLEDevice::init("ESP32");
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new ServerCallbacks());
  BLEService* pService = pServer->createService(SERVICE_UUID);

  // Temperature characteristic — READ + NOTIFY
  pTempChar = pService->createCharacteristic(
    TEMP_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  pTempChar->addDescriptor(new BLE2902());

  // Humidity characteristic — READ + NOTIFY
  pHumChar = pService->createCharacteristic(
    HUM_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  pHumChar->addDescriptor(new BLE2902());

  // Pressure characteristic — READ + NOTIFY
  pPressChar = pService->createCharacteristic(
    PRESS_CHARACTERISTIC_UUID,
    BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
  );
  pPressChar->addDescriptor(new BLE2902());

  // Set initial values
  pTempChar->setValue("0.0");
  pHumChar->setValue("0.0");
  pPressChar->setValue("0.0");

  // Start the service
  pService->start();

  // Start BLE Device Advertising
  BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);
  BLEDevice::startAdvertising();

  Serial.println("BLE advertising started. Waiting for client...");
}

void loop() {
  unsigned long now = millis();

  // Sample and notify on schedule
  if (now - lastSampleMs >= SAMPLE_INTERVAL_MS) {
    lastSampleMs = now;

    float tempC     = bme.readTemperature();   // °C
    float humidity  = bme.readHumidity();      // %
    float pressurePa  = bme.readPressure();    // Pa
    float pressureHPa = pressurePa / 100.0F;   // hPa

    Serial.printf("Temp: %.1f °C  Hum: %.1f %%  Press: %.1f hPa\n",
                   tempC, humidity, pressureHPa);

      // Notify BLE client with sensor readings if a BLE client is connected
      if (deviceConnected) {
        notifyFloat(pTempChar,  tempC);
        notifyFloat(pHumChar,   humidity);
        notifyFloat(pPressChar, pressureHPa);
      }
  }

  // Handle BLE reconnect after unexpected disconnect
  if (!deviceConnected && oldDeviceConnected) {
    delay(500);
    pServer->startAdvertising();
    Serial.println("Restarted advertising.");
    oldDeviceConnected = false;
  }

  if (deviceConnected && !oldDeviceConnected) {
    oldDeviceConnected = true;
    Serial.println("BLE client connected.");
  }
}

Afficher le code brut

Comment fonctionne le code

En résumé, ce code configure un serveur BLE avec le service de détection environnementale avec trois caractéristiques : température, humidité et pression. Lorsqu’un client BLE se connecte, il peut lire les données du capteur. Le code gère également les événements de connexion et de déconnexion des appareils.

Y compris les bibliothèques

Tout d’abord, vous devez importer les bibliothèques suivantes pour gérer Bluetooth.

#include 
#include 
#include 
#include 

Ceux-ci sont utilisés pour connecter et lire le capteur BME280 :

#include 
#include 

BME280

Définissez les broches auxquelles le capteur BME280 est connecté. Nous utilisons les GPIO 21 et 22.

// BME280 GPIOs
#define SDA_PIN 21
#define SCL_PIN 22

Créez une instance d’Adafruit_BME280 appelée bme.

Adafruit_BME280 bme;

Définitions UUID

Ensuite, vous définissez les UUID pour le service et les caractéristiques. Les UUID officiels définis dans le SIG pour le service de détection environnementale et les caractéristiques de température, d’humidité et de pression sont les suivants :

// BLE UUIDs 
// Environmental Sensing Service
#define SERVICE_UUID              "181A"
// Temperature
#define TEMP_CHARACTERISTIC_UUID  "2A6E"
// Humidity
#define HUM_CHARACTERISTIC_UUID   "2A6F"
// Pressure
#define PRESS_CHARACTERISTIC_UUID "2A6D"

Variables BLE globales

Ensuite, vous créez des variables globales à utiliser plus tard dans votre code.

// BLE variables
BLEServer*         pServer            = nullptr;
BLECharacteristic* pTempChar          = nullptr;
BLECharacteristic* pHumChar           = nullptr;
BLECharacteristic* pPressChar         = nullptr;
bool               deviceConnected    = false;
bool               oldDeviceConnected = false;
  • pServer : pointeur vers l’objet BLEServer ;
  • pTempChar : pointeur vers le BLECharacteristic pour la lecture de la température ;
  • pHumChar : pointeur vers la caractéristique BLE pour la lecture de l’humidité ;
  • pPressChar : pointeur vers le BLECharacteristic pour la lecture de la pression ;
  • deviceConnected : une variable booléenne pour savoir si un appareil BLE est connecté ;
  • oldDeviceConnected : une variable booléenne pour suivre l’état de la connexion précédente.

Serveur BLE et rappels

Ensuite, vous créez plusieurs fonctions de rappel. ServerCallbacks définit une fonction de rappel pour les événements de connexion et de déconnexion de périphérique. Dans ce cas, nous modifions la valeur de la variable deviceConnected en true ou false en fonction de l’état de la connexion.

// BLE server callbacks
class ServerCallbacks : public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) override {
    deviceConnected = true;
    Serial.println("BLE client connected.");
  }
  void onDisconnect(BLEServer* pServer) override {
    deviceConnected = false;
    Serial.println("BLE client disconnected.");
  }
};

Notifier les valeurs

La fonction notifyFloat() écrit une valeur flottante sur un BLECharacteristic spécifique. Puisque toutes nos valeurs sont des flottants avec plusieurs nombres décimaux, nous les formatons d’abord à une décimale.

void notifyFloat(BLECharacteristic* pChar, float value) {
  char buf[16];
  snprintf(buf, sizeof(buf), "%.1f", value);

Nous définissons la valeur caractéristique.

pChar->setValue(buf);

Et puis, nous informons le client connecté que la caractéristique a changé.

pChar->notify();

installation()

Dans setup(), initialisez la communication série pour le débogage.

Serial.begin(115200);

Initialisez le capteur BME280.

// Initialize BME280 Sensor
Wire.begin(SDA_PIN, SCL_PIN);
if (!bme.begin(0x76)) { 
  Serial.println("BME280 not found!");
  while(1); 
}

Initialisez l’ESP32 en tant que périphérique BLE appelé ESP32. Vous pouvez l’appeler n’importe quel autre nom.

BLEDevice::init("ESP32");

Ensuite, créez un serveur BLE et définissez ses rappels pour la connexion et la déconnexion.

pServer = BLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());

Créez un service BLE avec l’UUID que nous avons défini précédemment.

BLEService* pService = pServer->createService(SERVICE_UUID);

Créez les caractéristiques BLE de température, d’humidité et de pression (dans le service que nous venons de créer) et définissez leurs propriétés (lire et notifier). Ajoutez des descripteurs BLE (BLE2902) à toutes les caractéristiques.

// Temperature characteristic — READ + NOTIFY
pTempChar = pService->createCharacteristic(
  TEMP_CHARACTERISTIC_UUID,
  BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pTempChar->addDescriptor(new BLE2902());

// Humidity characteristic — READ + NOTIFY
pHumChar = pService->createCharacteristic(
  HUM_CHARACTERISTIC_UUID,
  BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pHumChar->addDescriptor(new BLE2902());

// Pressure characteristic — READ + NOTIFY
pPressChar = pService->createCharacteristic(
  PRESS_CHARACTERISTIC_UUID,
  BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pPressChar->addDescriptor(new BLE2902());

Remarque : BLE2902 est un descripteur spécifique souvent utilisé pour la configuration des caractéristiques du client (CCC). Les descripteurs CCC sont utilisés pour configurer la manière dont un client (l’appareil qui se connecte au serveur) souhaite être averti ou indiqué des changements dans la valeur d’une caractéristique. En termes plus simples, ils contrôlent si le client doit recevoir des notifications ou des indications lorsque la valeur de la caractéristique associée change.

En ajoutant des descripteurs BLE2902 à nos caractéristiques, vous permettez aux clients de configurer la manière dont ils souhaitent être avertis ou mis à jour lorsque les valeurs de ces caractéristiques changent. Les clients peuvent utiliser ces descripteurs pour activer ou désactiver les notifications ou les indications, en fonction de leurs préférences ou exigences en matière de mises à jour en temps réel depuis le serveur ESP32.

Définissez les valeurs initiales des caractéristiques sur 0,0.

// Set initial values
pTempChar->setValue("0.0");
pHumChar->setValue("0.0");
pPressChar->setValue("0.0");

Démarrez le service BLE.

// Start the service
pService->start();

Et enfin, configurez les paramètres de publicité et lancez la publicité.

// Start BLE Device Advertising
BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->setMinPreferred(0x0);
BLEDevice::startAdvertising();

boucle()

Dans la boucle(), obtenez de nouvelles valeurs de capteur tous les SAMPLE_INTERVAL_MS.

unsigned long now = millis();

// Sample and notify on schedule
if (now - lastSampleMs >= SAMPLE_INTERVAL_MS) {
  lastSampleMs = now;

  float tempC     = bme.readTemperature();   // °C
  float humidity  = bme.readHumidity();      // %
  float pressurePa  = bme.readPressure();    // Pa
  float pressureHPa = pressurePa / 100.0F;   // hPa

  Serial.printf("Temp: %.1f °C  Hum: %.1f %%  Press: %.1f hPa\n",
                 tempC, humidity, pressureHPa);

Si un appareil BLE est connecté (deviceConnected est vrai), informez le client des nouvelles lectures.

// Notify BLE client with sensor readings if a BLE client is connected
if (deviceConnected) {
  notifyFloat(pTempChar,  tempC);
  notifyFloat(pHumChar,   humidity);
  notifyFloat(pPressChar, pressureHPa);
}

Si un appareil se déconnecte et que oldDeviceConnected est vrai, il redémarre la publicité et enregistre un message.
Si un appareil se connecte et que oldDeviceConnected est faux, il enregistre un message (vous pouvez ajouter ici votre propre logique pour les actions à entreprendre lors de la connexion).

// Handle BLE reconnect after unexpected disconnect
if (!deviceConnected && oldDeviceConnected) {
  delay(500);
  pServer->startAdvertising();
  Serial.println("Restarted advertising.");
  oldDeviceConnected = false;
}

if (deviceConnected && !oldDeviceConnected) {
  oldDeviceConnected = true;
  Serial.println("BLE client connected.");
}

Téléchargement du code

Téléchargez le code sur votre carte ESP32. Après le téléchargement, ouvrez le Serial Monitor et redémarrez votre carte.

Vous verrez qu’il a initialisé le service BLE et attend une connexion client.

Appareil ESP32 BLE avec BME280 en attente d'une connexion.

Création de l’application Web BLE

Maintenant que vous avez défini l’ESP32 comme client BLE, nous allons créer l’application Web afin de pouvoir interagir avec l’ESP32 via BLE à l’aide de notre navigateur Web.

Application Web BLE - ESP32 - Service de détection environnementale

Alternativement, vous pouvez utiliser notre application Web en accédant à cette URL :

Page HTML

Créez un fichier HTML appelé index.html avec le code suivant (il contient à la fois le HTML pour créer la page Web et le JavaScript pour gérer Web Bluetooth).





    ESP32 Web BLE - SENSOR
    
    
    
    
    





    
    
        📶  Connect to BLE device
        ❌  Disconnect
        

Disconnected

🌡

Temperature

-- °C

No reading

°C °F

💧

Humidity

-- %

No reading

Pressure

-- hPa

No reading

Afficher le code brut

Comment ça marche ?

Ce code HTML et JavaScript crée une application Web qui vous permet de vous connecter à un appareil ESP32 via Bluetooth Low Energy (BLE). L’application fournit une interface utilisateur pour afficher les données « envoyées » par l’ESP32.

Jetons un coup d’œil aux parties pertinentes du fichier HTML qui créent les éléments de notre page.

Nous créons d’abord une carte qui comprend les boutons Connecter/Déconnecter et un paragraphe pour afficher l’état de la connexion BLE.

Application Web BLE ESP32 : connecter/déconnecter l'appareil


    📶  Connect to BLE device
    ❌  Disconnect
    

Disconnected

Ensuite, nous disposons de cartes pour afficher les lectures actuelles du capteur et les horodatages correspondants.

Application ESP32 Web BLE - Afficher les données du capteur

(...)

C’est la carte pour afficher la température. Notez que l’endroit où nous afficherons la température réelle a l’identifiant tempValue et que l’endroit où afficher l’horodatage a l’identifiant tempTimestamp. Ceci est important dans la section JavaScript du code.


    🌡
    

Temperature

-- °C

No reading

°C °F

Dans cette carte particulière, nous ajoutons également un interrupteur à bascule qui nous permet de modifier les valeurs de température entre Celsius et Fahrenheit.

No reading

°C °F

C’est la section pour afficher la lecture d’humidité. L’endroit où la valeur d’humidité sera affichée a l’identifiant humValue et le humTimestamp pour l’horodatage.


    💧
    

Humidity

-- %

No reading

Et c’est la section pour afficher la lecture de pression avec les identifiants pressValue et pressTimestamp pour la lecture de pression et l’horodatage correspondant.

Pressure

-- hPa

No reading

Nous afficherons également l’horodatage de la réception de la valeur dans le paragraphe suivant.

Last reading:

Enfin, nous avons une section pour les graphiques. Nous allons créer les graphiques à l’aide de la bibliothèque Chart.js. Les emplacements d’affichage des graphiques ont les identifiants suivants : tempChart, humChart et pressChart.


Application Web BLE ESP32 - Afficher les lectures du capteur

JavaScript-WebBLE

Ensuite, à l’intérieur des balises, nous avons le code JavaScript chargé de se connecter/déconnecter avec le client BLE et d’afficher les données.

Éléments DOM

Tout d’abord, nous sélectionnons les éléments HTML et leur attribuons un nom de variable pour une manipulation plus facile tout au long du code.

// DOM Elements
const connectButton    = document.getElementById('connectBleButton');
const disconnectButton = document.getElementById('disconnectBleButton');
const bleStateEl       = document.getElementById('bleState');
const bleDot           = document.getElementById('bleDot');

const tempValueEl    = document.getElementById('tempValue');
const humValueEl     = document.getElementById('humValue');
const pressValueEl   = document.getElementById('pressValue');
const tempTimestamp  = document.getElementById('tempTimestamp');
const humTimestamp   = document.getElementById('humTimestamp');
const pressTimestamp = document.getElementById('pressTimestamp');
const tempUnitLabel  = document.getElementById('tempUnitLabel');

UUID BLE

Ensuite, nous avons le nom de l’appareil BLE et les UUID BLE pour le service de détection environnementale et les caractéristiques de température, d’humidité et de pression. Ce sont les données que nous rechercherons dans le client ESP32 GATT.

var deviceName="ESP32";
var bleService="0000181a-0000-1000-8000-00805f9b34fb";
var tempCharUUID        = '00002a6e-0000-1000-8000-00805f9b34fb';
var humCharUUID         = '00002a6f-0000-1000-8000-00805f9b34fb';
var pressCharUUID       = '00002a6d-0000-1000-8000-00805f9b34fb';

Remarque : dans ce code, nous utilisons toujours les UUID officiels pour le service et les caractéristiques que nous recherchons, mais nous utilisons les UUID étendus.

Nous avons constaté que les UUID raccourcis ne fonctionnaient pas dans l’application Bluefy (je ne sais pas pourquoi. Si vous avez des idées, n’hésitez pas à nous le faire savoir). Dans tous les cas, les UUID raccourcis fonctionnaient bien dans notre navigateur Web Chrome (Windows). Si vous souhaitez utiliser les UUID raccourcis, utilisez plutôt les lignes suivantes.

var bleService          = 0x181A;
var tempCharUUID        = 0x2A6E;
var humCharUUID         = 0x2A6F;
var pressCharUUID       = 0x2A6D;

Définir des variables globales

Ensuite, nous créons des variables globales pour gérer la communication Bluetooth et la découverte d’appareils plus tard dans notre code.

// BLE state
var bleServer;
var tempCharFound;
var humCharFound;
var pressCharFound;
var userDisconnected = false;

Nous créons également des variables pour gérer les données des capteurs. Nous utilisons les objets tempData, humData et pressData pour contenir les données liées à chaque lecture.

// Sensor state
var currentUnit="C";
var lastTempC   = null;
const MAX_POINTS = 60;
var tempData  = { labels: [], valuesC: [], valuesF: [] };
var humData   = { labels: [], values: [] };
var pressData = { labels: [], values: [] };

Création des graphiques

La fonction drawChart() créera les graphiques. Il accepte comme arguments le canvasId (l’ID de l’élément HTML où nous placerons le graphique), la couleur et l’étiquette de l’axe y.

function drawChart(canvasId, color, yLabel) {
    return new Chart(document.getElementById(canvasId), {
        type: 'line',
        data: {
            labels: [],
            datasets: [{
                label: yLabel,
                borderColor: color,
                backgroundColor: color + '18',
                borderWidth: 2,
                pointRadius: 3,
                pointHoverRadius: 5,
                tension: 0.3,
                fill: true,
                data: []
            }]
        },
        options: {
            responsive: true,
            maintainAspectRatio: false,
            animation: { duration: 300 },
            interaction: { mode: 'index', intersect: false },
            scales: {
                x: {
                    ticks: { font: { size: 11 }, maxRotation: 45, autoSkip: true, maxTicksLimit: 10 },
                    grid: { color: 'rgba(0,0,0,0.05)' }
                },
                y: {
                    title: { display: true, text: yLabel, font: { size: 11 } },
                    grid: { color: 'rgba(0,0,0,0.05)' }
               }
            },
            plugins: { legend: { display: false } }
        }
    });
}

Pour en savoir plus sur la création de graphiques et sur la manière de modifier leurs propriétés et leur apparence, consultez la documentation charts.js ici.

Ensuite, nous appelons la fonction drawChart() pour créer les trois graphiques.

var tempChart  = drawChart('tempChart',  '#e07b3a', 'Temperature (°C)');
var humChart   = drawChart('humChart',   '#3a90c4', 'Humidity (%)');
var pressChart = drawChart('pressChart', '#7c5cbf', 'Pressure (hPa)');

Unités de température

La section suivante gère la modification de l’unité des valeurs de température. Nous devons obtenir la sélection d’unité souhaitée et gérer l’affichage de l’unité sur les cartes (fonction setTempUnit()).

// Temperature unit toggle
function setTempUnit(unit) {
    currentUnit = unit;
    document.getElementById('btnC').classList.toggle('active', unit === 'C');
    document.getElementById('btnF').classList.toggle('active', unit === 'F');
    tempUnitLabel.innerHTML = ' °' + unit;
    refreshTempDisplay();
    refreshTempChart();
}

La fonction qui convertit réellement les valeurs (cToF() avec une valeur décimale) :

function cToF(c) { return (c * 9 / 5 + 32).toFixed(1); }

Une fonction pour rafraîchir la carte des températures :

function refreshTempDisplay() {
    if (lastTempC === null) return;
    tempValueEl.textContent = currentUnit === 'C'
        ? parseFloat(lastTempC).toFixed(1)
        : cToF(parseFloat(lastTempC));
}

Et une fonction pour rafraîchir le diagramme de température lorsque l’on change l’unité de température.

function refreshTempChart() {
    tempChart.data.labels                 = tempData.labels;
    tempChart.data.datasets[0].data       = currentUnit === 'C' ? tempData.valuesC : tempData.valuesF;
    tempChart.data.datasets[0].label      = currentUnit === 'C' ? 'Temperature (°C)' : 'Temperature (°F)';
    tempChart.options.scales.y.title.text = currentUnit === 'C' ? 'Temperature (°C)' : 'Temperature (°F)';
    tempChart.update();
}

Ajouter des données aux graphiques

La fonction pushPoint() ajoutera des données aux objets de données que nous avons créés précédemment (tempData, humData et pressData) jusqu’à un maximum de 60 points (définis dans la variable MAX_POINTS). Ensuite, il ajoute les nouvelles valeurs de données aux graphiques.

function pushPoint(dataObj, chart, label, value, extraValue = null) {
    dataObj.labels.push(label);
    if (extraValue !== null) {
        dataObj.valuesC.push(value);
        dataObj.valuesF.push(extraValue);
    } else {
        dataObj.values.push(value);
    }
    if (dataObj.labels.length > MAX_POINTS) {
        dataObj.labels.shift();
        if (extraValue !== null) {
            dataObj.valuesC.shift();
            dataObj.valuesF.shift();
        } else {
            dataObj.values.shift();
        }
    }
    chart.data.labels = dataObj.labels;
    if (extraValue !== null) {
        chart.data.datasets[0].data = currentUnit === 'C' ? dataObj.valuesC : dataObj.valuesF;
    } else {
        chart.data.datasets[0].data = dataObj.values;
    }
    chart.update('none');
}

Nous appellerons cette fonction plus tard lorsque nous serons informés de nouvelles valeurs caractéristiques.

Affectation d’événements aux boutons

Presque à la fin du code, il y a une section où nous ajoutons des écouteurs d’événements aux boutons pour déclencher des actions lorsqu’ils sont cliqués (nous verrons le reste du code plus tard).

Bouton Se connecter au périphérique BLE

Le bouton Connect To BLE Device déclenchera la fonction connectToDevice(). Mais d’abord, nous vérifions si l’API JavaScript Web BLE est disponible dans votre navigateur avant de continuer, et nous affichons un message sur le bleStateContainer au cas où Web BLE ne serait pas pris en charge.

connectButton.addEventListener('click', () => {
    if (isWebBluetoothEnabled()) connectToDevice();
});

Pour vérifier si le Web Bluetooth est activé dans votre navigateur, nous avons créé une fonction appelée isWebBluetoothEnabled(). La méthode qui vérifie si Web BLE est activé est nagivator.bluetooth.

// Web Bluetooth availability check
function isWebBluetoothEnabled() {
    if (!navigator.bluetooth) {
        setBleDisconnected('Web Bluetooth not available in this browser');
        return false;
    }
    return true;
}

Bouton Déconnecter le périphérique BLE

Le bouton Déconnecter le périphérique BLE appellera la fonction déconnexionDevice.

disconnectButton.addEventListener('click', disconnectDevice);

Connexion à l’appareil BLE et recherche de services et de caractéristiques

La fonction connectToDevice() est déclenchée lorsque vous cliquez sur le bouton Connect to BLE Device. Cette fonction recherche l’appareil BLE, le service et les caractéristiques que nous avons définies précédemment.

function connectToDevice(){

Les lignes de code suivantes recherchent les appareils BLE avec le service et le nom BLE que nous avons définis.

try {
    const device = await navigator.bluetooth.requestDevice({
    filters: [{ name: deviceName }],
    optionalServices: [bleService]
});

Une fois connecté à un appareil, nous ajoutons un écouteur d’événements à notre appareil, au cas où il se déconnecterait (il appellera la fonction onDisconnected).

device.addEventListener('gattserverdisconnected', onDisconnected);

Depuis l’appareil, nous pouvons obtenir notre serveur GATT (la structure hiérarchique qui stocke les données dans le protocole BLE). Nous sauvegardons notre serveur GATT dans notre variable globale bleServer. Depuis le serveur GATTT, nous pouvons obtenir le service avec l’UUID que nous avons défini au début du code, service.

 bleServer = gattServer;
 setBleConnected(gattServer.device.name);

 const service = await gattServer.getPrimaryService(bleService);

Ensuite, nous appellerons la fonction SubscribeChar() qui écoutera les nouvelles données chaque fois que la valeur de la caractéristique change.

await subscribeChar(service, tempCharUUID, handleTemp, v => { tempCharFound = v; });
await subscribeChar(service, humCharUUID, handleHum, v => { humCharFound = v; });
await subscribeChar(service, pressCharUUID, handlePress, v => { pressCharFound = v; });

Lorsque nous trouvons les caractéristiques de nos capteurs, nous les attribuons aux variables temCharFound, humCharFound et pressCharFound correspondantes. Nous ajoutons un écouteur d’événement à nos caractéristiques pour gérer ce qui se passe lorsque les valeurs des caractéristiques changent. Nous appelons les fonctions handleTemp, handleHum ou handlePres. Nous démarrons également des notifications sur ces caractéristiques. Enfin, nous renvoyons la valeur actuelle inscrite sur la caractéristique.

async function subscribeChar(service, uuid, handler, storeFn) {
    try {
        const char = await service.getCharacteristic(uuid);
        storeFn(char);
            
        char.addEventListener('characteristicvaluechanged', handler);
        await char.startNotifications();            
        try {
            const val = await char.readValue();
            await new Promise(resolve => setTimeout(resolve, 50));
            handler({ target: { value: val } });
        } catch (readErr) {
            console.warn('Initial read failed for', uuid, ':', readErr);
        }
            
        console.log(`Subscribed to ${uuid}`);
        return char;
    } catch (err) {
        console.warn('Could not subscribe to', uuid, ':', err);
        throw err;
    }
}

Gérer le changement de caractéristique

Les fonctions handleTemp(), handleHum() et handlePres() seront appelées lorsque la valeur caractéristique correspondante change. Ces fonctions sont très similaires. Ils obtiennent la valeur caractéristique, l’horodatage et transmettent les nouvelles données aux objets de données correspondants. Ils mettent également à jour l’élément HTML d’horodatage avec l’heure.

function handleTemp(event) {
    var val = parseFloat(new TextDecoder().decode(event.target.value));
    if (isNaN(val)) return;
    lastTempC = val;
    refreshTempDisplay();
    var ts = getTime();
    tempTimestamp.textContent="Last reading: " + ts;
    const valC = parseFloat(val.toFixed(1));
    const valF = parseFloat(cToF(val));
    pushPoint(tempData, tempChart, ts, valC, valF);
}

function handleHum(event) {
    var val = parseFloat(new TextDecoder().decode(event.target.value));
    if (isNaN(val)) return;
    humValueEl.textContent = val.toFixed(1);
    var ts = getTime();
    humTimestamp.textContent="Last reading: " + ts;
    pushPoint(humData, humChart, ts, parseFloat(val.toFixed(1)));
}

function handlePress(event) {
    var val = parseFloat(new TextDecoder().decode(event.target.value));
    if (isNaN(val)) return;
    pressValueEl.textContent = val.toFixed(1);
    var ts = getTime();
    pressTimestamp.textContent="Last reading: " + ts;
    pushPoint(pressData, pressChart, ts, parseFloat(val.toFixed(1)));
}

Déconnecter le périphérique BLE

Lorsque vous cliquez sur le bouton Déconnecter le périphérique BLE, la fonction déconnecterDevice() est appelée.

disconnectButton.addEventListener('click', disconnectDevice);

Cette fonction vérifie d’abord si nous sommes connectés au serveur. Ensuite, nous arrêtons les notifications sur le sensorCharacteristic, et nous nous déconnectons du serveur GATT.

function disconnectDevice() {
    if (!bleServer || !bleServer.connected);
        alert('Bluetooth is not connected.');
        return;
    }
    userDisconnected = true;
    const stops = [];
    if (tempCharFound) stops.push(tempCharFound.stopNotifications().catch(() => {}));
    if (humCharFound) stops.push(humCharFound.stopNotifications().catch(() => {}));
    if (pressCharFound) stops.push(pressCharFound.stopNotifications().catch(() => {}));
        
    Promise.all(stops)
        .then(() => bleServer.disconnect())
        .then(() => setBleDisconnected('Disconnected'))
        .catch(err => console.error('Disconnect error:', err));
}

Styliser l’application Web BLE (style.css)

Dans le même dossier que le fichier index.html, créez un nouveau fichier appelé style.css avec le code suivant pour styliser l’application.

* {
    box-sizing: border-box;
}

html, body {
    font-family: Arial, Helvetica, sans-serif;
    margin: 0;
    padding: 0;
    background-color: #f0f2f5;
}

.hidden {
    display: none !important;
}

.topnav {
    overflow: hidden;
    background-color: #0A1128;
    padding: 0 20px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.topnav h1 {
    font-size: 1.5rem;
    color: white;
    margin: 0;
    padding: 16px 0;
    text-align: center;
}

.content {
    padding: 24px 20px;
    max-width: 1100px;
    margin: 0 auto;
}

.connection-card {
    background: white;
    border-radius: 10px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.07);
    padding: 20px 24px;
    margin-bottom: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 16px;
}

.ble-status {
    display: flex;
    align-items: center;
    gap: 8px;
    background: #f1f1f1;
    border-radius: 20px;
    padding: 6px 14px;
    font-size: 0.85rem;
    color: #555;
}

.ble-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background-color: #d13a30;
    transition: background-color 0.4s;
}

.ble-dot.connected {
    background-color: #24af37;
}

button {
    color: white;
    padding: 11px 20px;
    border: none;
    cursor: pointer;
    border-radius: 6px;
    font-size: 0.9rem;
    font-weight: 600;
    transition: opacity 0.15s, transform 0.1s;
}

button:hover {
    opacity: 0.88;
}

button:active {
    transform: scale(0.97);
}

.connectButton    { background-color: #24af37; }
.disconnectButton { background-color: #d13a30; }

.sensor-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 16px;
    margin-bottom: 24px;
}

.sensor-card {
    background: white;
    border-radius: 10px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.07);
    padding: 20px 24px;
    text-align: center;
}

.sensor-card .sensor-icon {
    font-size: 2rem;
    margin-bottom: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 2.4rem;
}

.sensor-card .sensor-label {
    font-size: 1.1rem;
    color: #999;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 6px;
}

.sensor-card .sensor-value {
    font-size: 2.4rem;
    font-weight: 700;
    line-height: 1;
    margin-bottom: 4px;
}

.sensor-card .sensor-unit {
    font-size: 1rem;
    font-weight: 400;
    color: #888;
}

.sensor-card .sensor-timestamp {
    font-size: 0.75rem;
    color: #bbb;
    margin-top: 8px;
}

.sensor-card.temp  .sensor-value { color: #e07b3a; }
.sensor-card.hum   .sensor-value { color: #3a90c4; }
.sensor-card.press .sensor-value { color: #7c5cbf; }

.unit-toggle {
    display: inline-flex;
    background: #f1f1f1;
    border-radius: 50px;
    padding: 3px;
    margin-top: 10px;
}

.unit-btn {
    padding: 4px 14px;
    font-size: 0.78rem;
    font-weight: 600;
    border: none;
    border-radius: 50px;
    cursor: pointer;
    background: transparent;
    color: #666;
    transition: all 0.2s;
}

.unit-btn.active {
    background: #0A1128;
    color: white;
}

.charts-section {
    display: flex;
    flex-direction: column;
    gap: 20px;
    margin-bottom: 24px;
}

.chart-card {
    background: white;
    border-radius: 10px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.07);
    padding: 20px 24px;
}

.chart-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 16px;
    flex-wrap: wrap;
    gap: 10px;
}

.chart-card-header h2 {
    margin: 0;
    font-size: 1.5rem;
    color: #333;
    display: flex;
    align-items: center;
}

.chart-wrapper {
    position: relative;
    height: 220px;
}

.footer {
    text-align: center;
    padding: 22px;
    font-size: 1.1rem;
    color: #aaa;
}

.footer a {
    color: #1b8a94;
    text-decoration: none;
}

@media (max-width: 600px) {
    .topnav { padding: 12px 16px; }
    .content { padding: 16px 12px; }
}

Afficher le code brut

icône de favori

De plus, ajoutez le favicon suivant à votre dossier.

Test de l’application Web BLE

Après avoir créé tous les fichiers requis dans le même dossier, faites glisser le fichier index.html vers votre navigateur Web.

La page suivante s’ouvrira.

Application de capteur Web BLE ESP32

Cela fonctionnera à la fois sur les ordinateurs Windows et iOS. Dans ce cas, cela fonctionne car le navigateur Web exécutant la page Web se trouve sur l’hôte local.

Avec l’ESP32 exécutant le code que nous avons fourni précédemment, testons l’application Web.

Commencez par cliquer sur le bouton Se connecter au périphérique BLE. Une fenêtre apparaîtra et vous devriez voir le périphérique ESP32 BLE. Connectez-vous à cet appareil.

Application Web BLE - connectez-vous à ESP32

Vous verrez que l’état BLE passera à connecté et vous commencerez à recevoir les valeurs écrites par l’ESP32 sur les caractéristiques de température, d’humidité et de pression.

Application Web BLE connectée à ESP32

Simultanément, vous devriez recevoir les messages suivants dans le moniteur série Arduino indiquant que la connexion a réussi.

Client ESP32 BLE connecté

Revenons à l’application. Il affiche la lecture la plus récente et l’horodatage correspondant sur les cartes.

Application ESP32 Web BLE - Afficher les données du capteur

Et un tableau pour chaque caractéristique. Le graphique est automatiquement mis à jour à mesure que de nouvelles valeurs de capteur sont écrites dans les caractéristiques.

Application Web BLE ESP32 - Afficher les lectures du capteur

Hébergement de votre application Web BLE

Avec la configuration actuelle, vous ne pouvez vous connecter à l’ESP32 via BLE qu’en ouvrant le fichier index.html dans le navigateur Web de votre ordinateur. Si vous souhaitez l’ouvrir sur votre smartphone ou tout autre appareil, vous devrez copier ce fichier sur l’appareil, puis l’ouvrir sur le navigateur Web. Ce n’est pas très pratique.

La meilleure façon d’accéder à votre application Web sur n’importe quel appareil est d’héberger vos fichiers sur un serveur. Pour travailler avec BLE, les fichiers doivent être servis via HTTPS.

Dans ce cas, cela ne fonctionnera pas sur les appareils iOS. Vous devrez utiliser l’application Bluefy (navigateur Web BLE) dont nous avons parlé précédemment.

Pour héberger notre application Web, nous utiliserons les pages GitHub. Si vous n’avez pas de compte GitHub, créez-en un avant de continuer.

1. Sur le tableau de bord de votre compte GitHub, cliquez sur l’icône + et créez un nouveau référentiel.

GitHub Créer un nouveau référentiel pour le projet

2. La page suivante se chargera. Donnez un nom à votre référentiel et assurez-vous qu’il est défini sur Public. Ensuite, cliquez sur le bouton Créer un référentiel.

GitHub Ajouter le nom du référentiel et définir le référentiel sur Public Créer un nouveau

3. Cliquez sur le lien de téléchargement d’un fichier existant.

GitHub télécharger des fichiers vers le référentiel

4. Faites glisser vos fichiers index.html, style.css et favicon.ico vers le référentiel. Ensuite, cliquez sur le bouton Valider les modifications.

Les fichiers GitHub ont téléchargé les modifications de validation

5. Ensuite, accédez à Paramètres > Pages et assurez-vous que les options sont surlignées en rouge ci-dessous. Enfin, cliquez sur le bouton Enregistrer.

GitHub Définir les pages GitHub et les publier

Après la soumission, attendez quelques minutes que la page Web soit disponible. Votre application Web sera dans le domaine suivant :

YOUR_GITHUB_USERNAME.github.io/YOUR_REPOSITORY_NAME

Dans notre cas, il est disponible sur la page web suivante : https://ruisantosdotme.github.io/esp32-web-ble-sensor/

https://ruisantosdotme.github.io/esp32-web-ble-sensor/

Démonstration

Désormais, vous pouvez accéder à votre application Web BLE sur n’importe quel appareil (prenant en charge Web BLE) avec un navigateur Web en accédant à cette URL. Ensuite, vous pouvez vous connecter à l’ESP32 via BLE à l’aide de cet appareil et voir les données en direct de température, d’humidité et de pression du BME280. Vous modifiez facilement ce projet pour afficher les données de n’importe quel autre capteur, comme un capteur de fréquence cardiaque.

Si vous utilisez un appareil iOS, vous devez ouvrir l’application Bluefy, puis insérer l’URL de votre application afin de pouvoir utiliser Web BLE.

Conclusion

Dans ce didacticiel, vous avez découvert la technologie Web BLE. En termes simples, il s’agit d’une API JavaScript qui nous permet de créer des applications Web pour interagir avec les appareils BLE à partir de n’importe quel navigateur Web prenant en charge Web BLE.

Vous avez appris à configurer l’ESP32 en tant qu’appareil BLE avec le service de détection environnementale avec des caractéristiques de température, d’humidité et de pression.

Nous espérons que vous avez trouvé ce tutoriel utile. Nous avons d’autres guides sur l’ESP32 et le Bluetooth qui pourraient vous plaire :

Vous souhaitez en savoir plus sur l’ESP32 ? Consultez toutes nos ressources :

Merci d’avoir lu

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

Youtube video

  • Outil de test RF ESP32 DIV V2.0 prenant en charge la numérisation WiFi BT BLE Analyse d'usurpation Sub GHz Capture de signal et capture à distance infrarouge
  • Bbajszx Carte de Lecture ESP8266 BME280 avec écran de 0, 96 Pouces et entrée Type-C 5 V pour Les projets électroniques compacts, la visualisation de données et la Construction de prototypes