Browse Source

Suppresion support ESP32 et ajout support ESP32-S3

Gestion de la LED WS2812 pour indiquer l'état des modules
Mise à jour de la documentation pour refléter les changements matériels
master
scayac 2 months ago
parent
commit
2526d637eb
  1. 149
      README.md
  2. 60
      html/index.html
  3. 19
      platformio.ini
  4. 137
      src/main.cpp

149
README.md

@ -1,13 +1,10 @@
# BleQuiz # BleQuiz
Application HTML5 de quiz temps réel pour plusieurs modules ESP32 via Bluetooth Low Energy (BLE) Application HTML5 de quiz temps réel pour plusieurs modules ESP32-S3 via Bluetooth Low Energy (BLE)
## 📋 Description ## 📋 Description
BleQuiz permet de créer un système de quiz interactif en temps réel où plusieurs ESP32 peuvent être connectés simultanément via Bluetooth. Chaque module ESP32 surveille des GPIOs (boutons) et envoie instantanément les événements à une interface web HTML5. BleQuiz permet de créer un système de quiz interactif en temps réel où plusieurs ESP32-S3 peuvent être connectés simultanément via Bluetooth. Chaque module ESP32-S3 surveille des GPIOs (boutons) et envoie instantanément les événements à une interface web HTML5.
**Cas d'usage :**
Quiz en classe, jeux de rapidité, systèmes de vote, buzzers interactifs.
**Adresse de test :** **Adresse de test :**
[https://blequiz.apps.christophe-scaya.fr/](https://blequiz.apps.christophe-scaya.fr/) (serveur de démonstration, utiliser le fichier `quiz_exemple.txt`) [https://blequiz.apps.christophe-scaya.fr/](https://blequiz.apps.christophe-scaya.fr/) (serveur de démonstration, utiliser le fichier `quiz_exemple.txt`)
@ -16,24 +13,57 @@ Quiz en classe, jeux de rapidité, systèmes de vote, buzzers interactifs.
### ESP32 (src/main.cpp) ### ESP32 (src/main.cpp)
Par défaut, le code surveille 4 GPIOs : **2, 4, 5, 6** (compatibles ESP32 Wrover et ESP32-C3) Par défaut, le code surveille 4 GPIOs : **2, 4, 5, 6** d'un module ESP32-S3 supermini générique.
Pour modifier les GPIOs surveillés, éditez cette ligne : Pour modifier les GPIOs surveillés, éditez cette ligne :
```cpp ```cpp
const int GPIO_PINS[] = {2, 4, 5, 6}; // GPIOs à surveiller (A, B, C, D) const int GPIO_PINS[] = {2, 4, 5, 6}; // GPIOs à surveiller (A, B, C, D)
``` ```
Pour changer le nom du module (important pour différencier plusieurs ESP32) : ### LED WS2812 (ESP32-S3)
```cpp
String moduleName = "ESP32-Module-1"; // Changer pour chaque ESP32 Le projet supporte une LED WS2812 sur le **GPIO 48** (ESP32-S3) pour indiquer l'état du module :
```
**États de la LED** :
- ⚪ **Blanc clignotant** (500ms) → Déconnecté de la page web
- ⚪ **Blanc fixe** → Connecté, en attente de réponse ou affichage des scores
- 🔴 **Rouge** → Bouton GPIO 2 pressé (réponse A)
- 🟢 **Vert** → Bouton GPIO 4 pressé (réponse B)
- 🔵 **Bleu** → Bouton GPIO 5 pressé (réponse C)
- 🟡 **Jaune** → Bouton GPIO 6 pressé (réponse D)
**Comportement selon les phases du quiz** :
1. **Connexion initiale** → ⚪ Blanc fixe (GPIO actifs)
2. **Question affichée** → ⚪ Blanc fixe (attente de réponse)
3. **Bouton pressé** → 🔴🟢🔵🟡 Couleur correspondante
4. **Résultats affichés** → LED garde sa couleur (GPIO désactivés)
5. **Question suivante** → ⚪ Blanc fixe (GPIO réactivés)
6. **Scores finaux** → ⚪ Blanc fixe (GPIO désactivés)
7. **Déconnexion** → ⚪ Blanc clignotant
**Configuration** : La bibliothèque `Adafruit NeoPixel` est automatiquement installée via PlatformIO.
### Identification automatique des modules (GPIO 8, 9, 10)
Chaque module ESP32-S3 peut être identifié automatiquement via 3 GPIOs configurés en **INPUT_PULLUP** :
### GPIOs avec Pull-up **Configuration des jumpers** (connecter à GND pour LOW, laisser ouvert pour HIGH) :
Les GPIOs sont configurés en **INPUT_PULLUP**, ce qui signifie : - **GPIO 8** = bit 0
- **État normal (non connecté)** : HIGH (3.3V) - **GPIO 9** = bit 1
- **État actif (connecté à GND)** : LOW (0V) - **GPIO 10** = bit 2
**Table d'identification** :
| GPIO 10 | GPIO 9 | GPIO 8 | Binaire | Nom du module |
|---------|--------|--------|---------|---------------|
| HIGH | HIGH | HIGH | 000 | **BleQuiz-1** |
| HIGH | HIGH | LOW | 001 | **BleQuiz-2** |
| HIGH | LOW | HIGH | 010 | **BleQuiz-3** |
| HIGH | LOW | LOW | 011 | **BleQuiz-4** |
| LOW | HIGH | HIGH | 100 | **BleQuiz-5** |
| LOW | HIGH | LOW | 101 | **BleQuiz-6** |
| LOW | LOW | HIGH | 110 | **BleQuiz-7** |
| LOW | LOW | LOW | 111 | **BleQuiz-8** |
Le système envoie une notification à la page HTML **quand un GPIO passe à l'état BAS**.
## 🚀 Installation et utilisation ## 🚀 Installation et utilisation
@ -45,32 +75,16 @@ Le système envoie une notification à la page HTML **quand un GPIO passe à l'
### 2. Configuration des ESP32 ### 2. Configuration des ESP32
Le projet supporte deux environnements (voir `platformio.ini`) : **Compiler et téléverser pour ESP32-S3** :
- **esp32dev** : ESP32 Wrover standard
- **esp32-c3-supermini** : Seeed XIAO ESP32-C3 (ou module générique ESP32-C3)
**Compiler et téléverser pour ESP32 Wrover** :
```bash ```bash
pio run -e esp32dev pio run -e esp32-s3-supermini
pio run -e esp32dev --target upload pio run -e esp32-s3-supermini --target upload
``` ```
**Compiler et téléverser pour ESP32-C3** :
```bash
pio run -e esp32-c3-supermini
pio run -e esp32-c3-supermini --target upload
```
**Monitorer le port série** (optionnel) : **Monitorer le port série** (optionnel) :
```bash ```bash
pio device monitor pio device monitor
``` ```
**Important** : Si vous utilisez plusieurs modules, modifiez le nom de chaque module dans `src/main.cpp` :
```cpp
String moduleName = "ESP32-Module-1"; // Changer pour Module-2, Module-3, etc.
```
### 3. Démarrer le serveur HTTPS ### 3. Démarrer le serveur HTTPS
**Important** : Web Bluetooth nécessite HTTPS (ou localhost en HTTP) **Important** : Web Bluetooth nécessite HTTPS (ou localhost en HTTP)
@ -114,7 +128,7 @@ https://localhost:8443
### 5. Utiliser l'application ### 5. Utiliser l'application
1. **Charger un fichier de questions** : Cliquez sur "Choisir un fichier" et sélectionnez votre fichier de quiz (voir `quiz_exemple.txt`) 1. **Charger un fichier de questions** : Cliquez sur "Choisir un fichier" et sélectionnez votre fichier de quiz (voir `quiz_exemple.txt`)
2. **Connecter les modules** : Cliquez sur "Connecter un module" et sélectionnez votre ESP32 2. **Connecter les modules** : Cliquez sur "Connecter un module" et sélectionnez votre ESP32-S3 dans la liste Bluetooth
3. **Lancer le quiz** : Naviguez entre les questions, les modules répondent en appuyant sur leurs boutons 3. **Lancer le quiz** : Naviguez entre les questions, les modules répondent en appuyant sur leurs boutons
4. **Répétez** pour connecter plusieurs modules simultanément 4. **Répétez** pour connecter plusieurs modules simultanément
@ -190,13 +204,6 @@ L'application web offre :
## ⚙ Personnalisation ## ⚙ Personnalisation
### Changer le nom du module ESP32
Dans `src/main.cpp`, modifiez :
```cpp
String moduleName = "ESP32-Module-1"; // Changer pour chaque ESP32 (Module-2, Module-3, etc.)
```
### Modifier les GPIOs surveillés ### Modifier les GPIOs surveillés
Dans `src/main.cpp`, adaptez selon votre matériel : Dans `src/main.cpp`, adaptez selon votre matériel :
@ -204,23 +211,13 @@ Dans `src/main.cpp`, adaptez selon votre matériel :
const int GPIO_PINS[] = {2, 4, 5, 6}; // GPIOs à surveiller const int GPIO_PINS[] = {2, 4, 5, 6}; // GPIOs à surveiller
``` ```
**GPIOs recommandés** :
- **ESP32 Wrover** : 2, 4, 5, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23
- **ESP32-C3** : 2, 3, 4, 5, 6, 7, 8, 9, 10
### Changer les UUID Bluetooth ### Changer les UUID Bluetooth
Dans `src/main.cpp` et `index.html`, modifiez (doit être identique des deux côtés) : Dans `src/main.cpp` et `index.html`, modifiez (doit être identique des deux côtés) :
```cpp ```cpp
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
``` #define COMMAND_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a9"
### Modifier le délai de lecture
Dans `src/main.cpp`, dernière ligne de `loop()` :
```cpp
delay(100); // Modifier selon vos besoins (en millisecondes)
``` ```
### Format du fichier de quiz ### Format du fichier de quiz
@ -252,12 +249,12 @@ Créez un fichier texte avec ce format (voir `quiz_exemple.txt`) :
## 🐛 Dépannage ## 🐛 Dépannage
### L'ESP32 n'apparaît pas dans la liste Bluetooth ### L'ESP32-S3 n'apparaît pas dans la liste Bluetooth
- Vérifiez que le module est alimenté correctement (USB ou externe 5V) - Vérifiez que le module est alimenté correctement (USB ou externe 5V)
- Consultez le moniteur série : `pio device monitor` pour voir les messages de démarrage - Consultez le moniteur série : `pio device monitor` pour voir les messages de démarrage
- Assurez-vous que le Bluetooth est activé sur votre ordinateur - Assurez-vous que le Bluetooth est activé sur votre ordinateur
- Sur Linux, vérifiez que BlueZ est à jour : `bluetoothctl --version` - Sur Linux, vérifiez que BlueZ est à jour : `bluetoothctl --version`
- Redémarrez l'ESP32 (bouton RESET ou débrancher/rebrancher) - Redémarrez l'ESP32-S3 (bouton RESET ou débrancher/rebrancher)
### Pas de données reçues dans l'interface web ### Pas de données reçues dans l'interface web
- Vérifiez que les UUID correspondent dans `src/main.cpp` et `index.html` - Vérifiez que les UUID correspondent dans `src/main.cpp` et `index.html`
@ -266,8 +263,8 @@ Créez un fichier texte avec ce format (voir `quiz_exemple.txt`) :
- Vérifiez que le module est bien connecté (voyant dans l'interface) - Vérifiez que le module est bien connecté (voyant dans l'interface)
### Déconnexions fréquentes ### Déconnexions fréquentes
- Réduisez la distance entre l'ESP32 et l'ordinateur (< 5 mètres) - Réduisez la distance entre l'ESP32-S3 et l'ordinateur (< 5 mètres)
- Assurez-vous que l'alimentation de l'ESP32 est stable (câble USB de qualité) - Assurez-vous que l'alimentation de l'ESP32-S3 est stable (câble USB de qualité)
- Évitez les interférences (WiFi 2.4GHz, micro-ondes) - Évitez les interférences (WiFi 2.4GHz, micro-ondes)
- Augmentez le délai dans la boucle principale si trop de données sont envoyées - Augmentez le délai dans la boucle principale si trop de données sont envoyées
@ -285,21 +282,28 @@ Créez un fichier texte avec ce format (voir `quiz_exemple.txt`) :
## 📝 Caractéristiques techniques ## 📝 Caractéristiques techniques
- **Protocole** : Bluetooth Low Energy (BLE 4.0+) - **Protocole** : Bluetooth Low Energy (BLE 4.0+)
- **Compatibilité ESP32** : ESP32 Wrover, ESP32-C3 (Seeed XIAO) - **LED WS2812** : Indicateur visuel d'état sur GPIO 48
- **GPIOs configurables** : 4 par défaut (extensible) - **Identification automatique** : Via GPIOs 8, 9, 10 (BleQuiz-1 à BleQuiz-8)
- **Connexions simultanées** : Jusqu'à 10 modules ESP32 - **GPIOs boutons** : 4 par défaut (2, 4, 5, 6)
- **Connexions simultanées** : Jusqu'à 8+ modules ESP32
- **Fréquence de mise à jour** : 100ms par défaut - **Fréquence de mise à jour** : 100ms par défaut
- **Portée Bluetooth** : ~10 mètres en intérieur - **Portée Bluetooth** : ~10 mètres en intérieur
- **Navigateurs supportés** : Chrome 56+, Edge 79+, Opera 43+ - **Navigateurs supportés** : Chrome 56+, Edge 79+, Opera 43+
- **Serveurs fournis** : Python 3 (SSL auto-signé) et Node.js - **Serveurs fournis** : Python 3 (SSL auto-signé) et Node.js
- **Bibliothèques** : Adafruit NeoPixel (pour LED WS2812)
## 🎯 Notes d'utilisation ## 🎯 Notes d'utilisation
- **Modules multiples** : Chaque module doit avoir un nom unique configuré dans `src/main.cpp` - **Identification automatique** : Les modules se nomment automatiquement BleQuiz-1 à BleQuiz-8 selon les GPIOs 8, 9, 10
- **Sécurité BLE** : Le code utilise un mode sans bonding (pas de mémorisation d'appairage) - **Sécurité BLE** : Le code utilise un mode sans bonding (pas de mémorisation d'appairage)
- **Web Bluetooth** : La page HTML doit obligatoirement être servie en HTTPS ou via localhost - **Web Bluetooth** : La page HTML doit obligatoirement être servie en HTTPS ou via localhost
- **Détection de changement** : Les événements GPIO sont envoyés instantanément lors des transitions HIGH→LOW - **Détection de changement** : Les événements GPIO sont envoyés instantanément lors des transitions HIGH→LOW
- **Mode Pull-up** : Les boutons doivent connecter le GPIO à GND (pas à VCC) - **Mode Pull-up** : Les boutons doivent connecter le GPIO à GND (pas à VCC)
- **LED WS2812** : Feedback visuel automatique sur ESP32-S3, la LED indique l'état de connexion et les réponses
- **Commandes BLE** :
- `START` : Active la détection GPIO (blanc fixe)
- `RESET` : Fige la LED, désactive les GPIO (affichage résultats)
- `SCORES` : Blanc fixe, GPIO désactivés (scores finaux)
## 🚀 Démarrage rapide (Linux) ## 🚀 Démarrage rapide (Linux)
@ -316,17 +320,6 @@ pio run -e esp32dev --target upload
# - Commencer le quiz ! # - Commencer le quiz !
``` ```
## 🔐 Sécurité
Le projet est conçu pour un usage éducatif et de démonstration. Pour un usage en production :
- **Authentification BLE** : Implémenter un système de pairing sécurisé
- **Chiffrement des données** : Activer le chiffrement des caractéristiques BLE
- **Certificat SSL valide** : Remplacer le certificat auto-signé par un certificat CA
- **Validation côté serveur** : Ajouter une validation des réponses côté serveur
- **Limitation de connexions** : Implémenter une limite et un contrôle d'accès
- **Logs d'audit** : Enregistrer les actions pour le suivi et la sécurité
## 📚 Ressources ## 📚 Ressources
- [Web Bluetooth API Documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API) - [Web Bluetooth API Documentation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API)
@ -337,15 +330,3 @@ Le projet est conçu pour un usage éducatif et de démonstration. Pour un usage
## 📄 Licence ## 📄 Licence
Ce projet est open source. Libre d'utilisation, modification et distribution. Ce projet est open source. Libre d'utilisation, modification et distribution.
## 👥 Contribution
Les contributions sont les bienvenues ! N'hésitez pas à :
- Signaler des bugs
- Proposer de nouvelles fonctionnalités
- Améliorer la documentation
- Soumettre des pull requests
---
**Créé avec ❤ pour l'éducation et l'apprentissage interactif**

60
html/index.html

@ -533,10 +533,11 @@
// Configuration BLE // Configuration BLE
const SERVICE_UUID = '4fafc201-1fb5-459e-8fcc-c5c9c331914b'; const SERVICE_UUID = '4fafc201-1fb5-459e-8fcc-c5c9c331914b';
const CHARACTERISTIC_UUID = 'beb5483e-36e1-4688-b7f5-ea07361b26a8'; const CHARACTERISTIC_UUID = 'beb5483e-36e1-4688-b7f5-ea07361b26a8';
const COMMAND_UUID = 'beb5483e-36e1-4688-b7f5-ea07361b26a9';
let questions = []; let questions = [];
let currentQuestionIndex = 0; let currentQuestionIndex = 0;
let connectedModules = new Map(); // moduleName -> { device, characteristic, answer, scores } let connectedModules = new Map(); // moduleName -> { device, characteristic, commandCharacteristic, answer, scores }
let resultsShown = false; let resultsShown = false;
const fileInput = document.getElementById('fileInput'); const fileInput = document.getElementById('fileInput');
@ -627,6 +628,7 @@
const server = await device.gatt.connect(); const server = await device.gatt.connect();
const service = await server.getPrimaryService(SERVICE_UUID); const service = await server.getPrimaryService(SERVICE_UUID);
const characteristic = await service.getCharacteristic(CHARACTERISTIC_UUID); const characteristic = await service.getCharacteristic(CHARACTERISTIC_UUID);
const commandCharacteristic = await service.getCharacteristic(COMMAND_UUID);
// Lire l'état initial // Lire l'état initial
const initialValue = await characteristic.readValue(); const initialValue = await characteristic.readValue();
@ -640,6 +642,7 @@
connectedModules.set(moduleName, { connectedModules.set(moduleName, {
device: device, device: device,
characteristic: characteristic, characteristic: characteristic,
commandCharacteristic: commandCharacteristic,
answer: null, answer: null,
totalScore: 0, totalScore: 0,
gpios: data.gpios gpios: data.gpios
@ -803,6 +806,55 @@
} }
showResultsBtn.disabled = true; showResultsBtn.disabled = true;
// Envoyer la commande RESET immédiatement à tous les modules
// (LED garde sa couleur, GPIO désactivés)
resetAllModules();
}
async function resetAllModules() {
console.log('Envoi de RESET à tous les modules...');
for (let [name, module] of connectedModules.entries()) {
try {
if (module.commandCharacteristic) {
const encoder = new TextEncoder();
await module.commandCharacteristic.writeValue(encoder.encode('RESET'));
console.log(`RESET envoyé à ${name}`);
}
} catch (error) {
console.error(`Erreur envoi RESET à ${name}:`, error);
}
}
}
async function sendCommandToAllModules(command) {
console.log(`Envoi de ${command} à tous les modules...`);
for (let [name, module] of connectedModules.entries()) {
try {
if (module.commandCharacteristic) {
const encoder = new TextEncoder();
await module.commandCharacteristic.writeValue(encoder.encode(command));
console.log(`${command} envoyé à ${name}`);
}
} catch (error) {
console.error(`Erreur envoi ${command} à ${name}:`, error);
}
}
}
async function sendScoresCommand() {
console.log('Envoi de SCORES à tous les modules...');
for (let [name, module] of connectedModules.entries()) {
try {
if (module.commandCharacteristic) {
const encoder = new TextEncoder();
await module.commandCharacteristic.writeValue(encoder.encode('SCORES'));
console.log(`SCORES envoyé à ${name}`);
}
} catch (error) {
console.error(`Erreur envoi SCORES à ${name}:`, error);
}
}
} }
function handleFileSelect(event) { function handleFileSelect(event) {
@ -997,6 +1049,9 @@
} }
} }
// Envoyer la commande START à tous les modules
sendCommandToAllModules('START');
// Mettre à jour les contrôles // Mettre à jour les contrôles
document.getElementById('progress').textContent = document.getElementById('progress').textContent =
`${currentQuestionIndex + 1} / ${questions.length}`; `${currentQuestionIndex + 1} / ${questions.length}`;
@ -1047,6 +1102,9 @@
} }
scoresDetails.innerHTML = html; scoresDetails.innerHTML = html;
// Envoyer la commande SCORES à tous les modules (blanc fixe, GPIO désactivés)
sendScoresCommand();
} }
window.disconnectModule = function(moduleName) { window.disconnectModule = function(moduleName) {

19
platformio.ini

@ -1,12 +1,11 @@
[env:esp32dev] [env:esp32-s3-supermini]
platform = espressif32 platform = espressif32
board = esp32dev board = esp32-s3-devkitc-1
framework = arduino framework = arduino
monitor_speed = 115200 board_upload.flash_size = 4MB
board_build.partitions = default.csv
[env:esp32-c3-supermini] build_flags =
platform = espressif32 -DARDUINO_USB_CDC_ON_BOOT=1
board = seeed_xiao_esp32c3 -DBOARD_HAS_PSRAM
board_build.mcu = esp32c3 lib_deps =
framework = arduino adafruit/Adafruit NeoPixel@^1.12.0
monitor_speed = 115200

137
src/main.cpp

@ -3,35 +3,91 @@
#include <BLEServer.h> #include <BLEServer.h>
#include <BLEUtils.h> #include <BLEUtils.h>
#include <BLE2902.h> #include <BLE2902.h>
#include <Adafruit_NeoPixel.h>
// Configuration LED WS2812
#define LED_PIN 48
#define LED_COUNT 1
Adafruit_NeoPixel led(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);
// Couleurs
#define COLOR_OFF led.Color(0, 0, 0)
#define COLOR_WHITE led.Color(255, 255, 255)
#define COLOR_RED led.Color(255, 0, 0)
#define COLOR_GREEN led.Color(0, 255, 0)
#define COLOR_BLUE led.Color(0, 0, 255)
#define COLOR_YELLOW led.Color(255, 255, 0)
// UUID pour le service et la caractéristique BLE // UUID pour le service et la caractéristique BLE
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define COMMAND_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a9"
// Configuration des GPIO à surveiller // Configuration des GPIO à surveiller
// GPIO compatibles ESP32 Wrover ET ESP32-C3 : 2, 4, 5, 6 // GPIO compatibles ESP32 Wrover ET ESP32-C3 : 2, 4, 5, 6
const int GPIO_PINS[] = {2, 4, 5, 6}; // GPIOs à surveiller (A, B, C, D) const int GPIO_PINS[] = {2, 4, 5, 6}; // GPIOs à surveiller (A, B, C, D)
const int NUM_PINS = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]); const int NUM_PINS = sizeof(GPIO_PINS) / sizeof(GPIO_PINS[0]);
// GPIO pour l'identification du module (8, 9, 10)
const int ID_GPIO_PINS[] = {8, 9, 10}; // Bit 0, Bit 1, Bit 2
const int NUM_ID_PINS = sizeof(ID_GPIO_PINS) / sizeof(ID_GPIO_PINS[0]);
// Variables globales // Variables globales
BLEServer* pServer = NULL; BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL; BLECharacteristic* pCharacteristic = NULL;
BLECharacteristic* pCommandCharacteristic = NULL;
bool deviceConnected = false; bool deviceConnected = false;
bool oldDeviceConnected = false; bool oldDeviceConnected = false;
uint8_t gpioStates = 0; // Stocke l'état des GPIOs (bit à bit) uint8_t gpioStates = 0; // Stocke l'état des GPIOs (bit à bit)
unsigned long lastBlinkTime = 0;
bool blinkState = false;
bool gpioEnabled = false; // false = GPIO désactivés (résultats ou scores), true = GPIO actifs
// Nom du module (peut être modifié pour chaque ESP32) // Nom du module (sera déterminé automatiquement)
String moduleName = "ESP32-Module-1"; String moduleName = "BleQuiz-1";
// Callback pour la caractéristique de commande
class CommandCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) {
std::string value = pCharacteristic->getValue();
if (value.length() > 0) {
String command = String(value.c_str());
Serial.println("Commande reçue: " + command);
if (command == "RESET") {
// Garder la LED dans sa couleur actuelle, désactiver les GPIO
gpioEnabled = false;
Serial.println("Résultats affichés - LED figée, GPIO désactivés");
} else if (command == "START") {
// Passer en blanc fixe, activer les GPIO
gpioEnabled = true;
led.setPixelColor(0, COLOR_WHITE);
led.show();
Serial.println("Question démarrée - Blanc fixe, GPIO actifs");
} else if (command == "SCORES") {
// Passer en blanc fixe, désactiver les GPIO
gpioEnabled = false;
led.setPixelColor(0, COLOR_WHITE);
led.show();
Serial.println("Scores affichés - Blanc fixe, GPIO désactivés");
}
}
}
};
class MyServerCallbacks: public BLEServerCallbacks { class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) { void onConnect(BLEServer* pServer) {
deviceConnected = true; deviceConnected = true;
Serial.println("Client connecté"); gpioEnabled = true;
led.setPixelColor(0, COLOR_WHITE);
led.show();
Serial.println("Client connecté - Blanc fixe");
}; };
void onDisconnect(BLEServer* pServer) { void onDisconnect(BLEServer* pServer) {
deviceConnected = false; deviceConnected = false;
Serial.println("Client déconnecté"); gpioEnabled = false;
Serial.println("Client déconnecté - Mode clignotant");
} }
}; };
@ -39,6 +95,31 @@ void setup() {
Serial.begin(115200); Serial.begin(115200);
Serial.println("Démarrage du module ESP32 Bluetooth..."); Serial.println("Démarrage du module ESP32 Bluetooth...");
// Initialiser la LED WS2812 (éteinte au démarrage)
led.begin();
led.setPixelColor(0, COLOR_OFF);
led.show();
// Configuration des GPIO d'identification (8, 9, 10) en entrée avec pull-up
for (int i = 0; i < NUM_ID_PINS; i++) {
pinMode(ID_GPIO_PINS[i], INPUT_PULLUP);
}
// Lire l'ID du module (GPIO 8=bit0, 9=bit1, 10=bit2)
uint8_t moduleId = 0;
for (int i = 0; i < NUM_ID_PINS; i++) {
if (digitalRead(ID_GPIO_PINS[i]) == LOW) {
moduleId |= (1 << i);
}
}
moduleId += 1; // ID de 1 à 8 (000=1, 001=2, ..., 111=8)
moduleName = "BleQuiz-" + String(moduleId);
Serial.print("ID du module détecté: ");
Serial.println(moduleId);
Serial.print("Nom du module: ");
Serial.println(moduleName);
// Configuration des GPIO en entrée avec pull-up // Configuration des GPIO en entrée avec pull-up
for (int i = 0; i < NUM_PINS; i++) { for (int i = 0; i < NUM_PINS; i++) {
pinMode(GPIO_PINS[i], INPUT_PULLUP); pinMode(GPIO_PINS[i], INPUT_PULLUP);
@ -73,6 +154,13 @@ void setup() {
// Créer un descripteur BLE2902 pour les notifications // Créer un descripteur BLE2902 pour les notifications
pCharacteristic->addDescriptor(new BLE2902()); pCharacteristic->addDescriptor(new BLE2902());
// Créer la caractéristique de commande (pour RESET)
pCommandCharacteristic = pService->createCharacteristic(
COMMAND_UUID,
BLECharacteristic::PROPERTY_WRITE
);
pCommandCharacteristic->setCallbacks(new CommandCallbacks());
// Démarrer le service // Démarrer le service
pService->start(); pService->start();
@ -92,11 +180,24 @@ void setup() {
} }
Serial.println("En attente de connexion..."); Serial.println("En attente de connexion...");
Serial.print("Nom du module: ");
Serial.println(moduleName);
} }
void loop() { void loop() {
// Gestion du clignotement blanc uniquement si déconnecté
if (!deviceConnected) {
unsigned long currentTime = millis();
if (currentTime - lastBlinkTime >= 500) {
lastBlinkTime = currentTime;
blinkState = !blinkState;
if (blinkState) {
led.setPixelColor(0, COLOR_WHITE);
} else {
led.setPixelColor(0, COLOR_OFF);
}
led.show();
}
}
// Lire l'état de toutes les GPIO // Lire l'état de toutes les GPIO
uint8_t currentStates = 0; uint8_t currentStates = 0;
for (int i = 0; i < NUM_PINS; i++) { for (int i = 0; i < NUM_PINS; i++) {
@ -106,6 +207,30 @@ void loop() {
} }
} }
// Détecter les changements d'état des GPIO (passage à LOW)
// Uniquement si connecté ET GPIO activés
uint8_t newPresses = currentStates & ~gpioStates;
if (newPresses != 0 && deviceConnected && gpioEnabled) {
// Allumer la LED selon le GPIO pressé
if (newPresses & (1 << 0)) { // GPIO 2
led.setPixelColor(0, COLOR_RED);
led.show();
Serial.println("GPIO 2 pressé - LED ROUGE");
} else if (newPresses & (1 << 1)) { // GPIO 4
led.setPixelColor(0, COLOR_GREEN);
led.show();
Serial.println("GPIO 4 pressé - LED VERTE");
} else if (newPresses & (1 << 2)) { // GPIO 5
led.setPixelColor(0, COLOR_BLUE);
led.show();
Serial.println("GPIO 5 pressé - LED BLEUE");
} else if (newPresses & (1 << 3)) { // GPIO 6
led.setPixelColor(0, COLOR_YELLOW);
led.show();
Serial.println("GPIO 6 pressé - LED JAUNE");
}
}
// Créer un message JSON avec l'état des GPIO // Créer un message JSON avec l'état des GPIO
String message = "{\"module\":\"" + moduleName + "\",\"gpios\":["; String message = "{\"module\":\"" + moduleName + "\",\"gpios\":[";
for (int i = 0; i < NUM_PINS; i++) { for (int i = 0; i < NUM_PINS; i++) {

Loading…
Cancel
Save