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.

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)

2. Pièces requises
Pour ce tutoriel, vous pouvez utiliser n’importe quel ESP32 de votre choix.

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 !

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.

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 :

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*).

*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).

- 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).

- 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.


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.

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.

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.

📶 Connect to BLE device
❌ Disconnect
Disconnected
Ensuite, nous disposons de cartes pour afficher les lectures actuelles du capteur et les horodatages correspondants.

(...)
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.

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.

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.

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.

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

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

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.

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.

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.

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

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.

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.

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 :

-
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
