diff --git a/modele/entete.typ b/modele/entete.typ index 943d0b9..cd75ef2 100644 --- a/modele/entete.typ +++ b/modele/entete.typ @@ -41,3 +41,6 @@ #show table.cell.where(y: 0): set text(fill: white, weight: "bold") #show figure.caption: set text(size: 8.5pt, style: "italic", fill: gris-doux) + +// Texte des tableaux aligné à gauche (la justification crée des blancs dans les colonnes étroites) +#show table: set par(justify: false) diff --git a/modules/00-installation.qmd b/modules/00-installation.qmd new file mode 100644 index 0000000..434e9cf --- /dev/null +++ b/modules/00-installation.qmd @@ -0,0 +1,115 @@ +--- +title: "Module 0 — Prérequis & Installation" +--- + +## Objectifs du module + +- Comprendre le rôle et les avantages de l'Arduino IDE pour programmer un ESP32-S3. +- Installer et configurer l'environnement de développement. +- Identifier et installer les pilotes nécessaires à la reconnaissance de la carte. +- Flasher un premier programme (Blink) et valider la chaîne complète (code → compilation → upload → exécution). + +## 1. Matériel utilisé dans cette formation + +Toute la formation s'appuie sur une carte de développement ESP32-S3-WROOM-1 (DevKitC-1 ou équivalent). Points clés à connaître dès maintenant : + +- Microcontrôleur Xtensa LX7 double cœur, cadencé jusqu'à 240 MHz. +- Connexion USB native (USB OTG) : pas besoin de convertisseur USB-série externe sur la plupart des DevKits S3. +- Une LED RGB adressable (NeoPixel / WS2812) intégrée sur la carte — nous l'utiliserons au Module 2. +- Wi-Fi 2,4 GHz + Bluetooth Low Energy (BLE) — attention : pas de Bluetooth Classic sur l'ESP32-S3. +- Alimentation 3,3 V logique (contrairement à l'Arduino Uno qui est en 5 V) : ne jamais appliquer plus de 3,3 V sur une broche GPIO. + +::: {.callout-note title="À vérifier avant de commencer"} +Le modèle exact de votre carte peut varier (nombre de broches, position de la LED NeoPixel, présence de PSRAM). Repérez sur votre carte la sérigraphie indiquant le numéro de chaque GPIO : elle servira de référence tout au long de la formation. +::: + +## 2. Installation de l'Arduino IDE + +### 2.1 Téléchargement + +Rendez-vous sur le site officiel arduino.cc/en/software et téléchargez la version 2.x de l'Arduino IDE (interface plus moderne, gestion de projets multiples, terminal série amélioré) pour votre système d'exploitation (Windows, macOS, Linux). + +### 2.2 Installation des pilotes USB + +Selon la puce USB-série présente sur votre carte (souvent inutile si la carte utilise l'USB natif du S3), il peut être nécessaire d'installer un pilote : + +- CP210x (Silicon Labs) — pour certains DevKits. +- CH340/CH343 — pour d'autres clones. + +Sur Windows, le Gestionnaire de périphériques doit afficher un port COM une fois la carte branchée. Sur macOS/Linux, la carte apparaît généralement automatiquement (/dev/tty.usbserial-\* ou /dev/ttyUSB\*/ttyACM\*). + +## 3. Ajout du support ESP32 dans l'Arduino IDE + +Par défaut, l'IDE ne connaît que les cartes Arduino officielles. Il faut ajouter le paquet de définitions Espressif : + +### Étapes + +- Ouvrir Fichier \> Préférences (ou Arduino IDE \> Réglages sur macOS). +- Dans « URL de gestionnaire de cartes supplémentaires », ajouter : + +```text +https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json +``` + +- Ouvrir Outils \> Type de carte \> Gestionnaire de cartes. +- Rechercher « esp32 » et installer le paquet « esp32 by Espressif Systems » (dernière version stable). +- Redémarrer l'IDE. + +## 4. Sélection et configuration de la carte + +Une fois le paquet installé : + +- Outils \> Type de carte \> ESP32 Arduino \> choisir « ESP32S3 Dev Module ». +- Outils \> Port : sélectionner le port série apparu à la connexion de la carte. +- Outils \> USB CDC On Boot : Enabled (recommandé pour voir les messages Serial dès le démarrage sur l'ESP32-S3). +- Outils \> Upload Speed : 921600 (par défaut, réduire en cas d'échec d'upload). + +::: {.callout-tip title="Astuce mode téléchargement"} +Si l'upload échoue avec un message « Failed to connect », maintenez le bouton BOOT appuyé, appuyez brièvement sur RESET, relâchez BOOT, puis relancez le téléversement. Ce geste force la carte en mode bootloader. +::: + +## 5. Premier programme : Blink + +Nous allons vérifier que toute la chaîne (code → compilation → upload → exécution) fonctionne, en faisant clignoter la LED intégrée. + +```cpp +// Sur la plupart des DevKitC ESP32-S3, la LED simple (non RGB) est sur la broche 2. +// Vérifiez la sérigraphie de votre carte : elle peut varier. +#define LED_PIN 2 + +void setup() { + pinMode(LED_PIN, OUTPUT); + Serial.begin(115200); + Serial.println("Demarrage du programme Blink"); +} + +void loop() { + digitalWrite(LED_PIN, HIGH); + delay(500); + digitalWrite(LED_PIN, LOW); + delay(500); + Serial.println("Clignotement..."); +} +``` + +Compilez avec le bouton ✓ (Vérifier), puis téléversez avec la flèche → (Téléverser). Ouvrez le Moniteur Série (Outils \> Moniteur Série, vitesse 115200 bauds) pour voir les messages s'afficher. + +## 6. Checklist de fin de module + +- [ ] Arduino IDE installé et à jour. +- [ ] Pilotes USB installés si nécessaire, port COM/tty visible. +- [ ] Paquet ESP32 (Espressif) installé via le gestionnaire de cartes. +- [ ] Carte « ESP32S3 Dev Module » sélectionnée avec le bon port. +- [ ] Programme Blink compilé, téléversé et fonctionnel. +- [ ] Moniteur série fonctionnel (messages visibles à 115200 bauds). + +## Exercice pratique + +Modifiez le programme Blink pour : + +- Faire clignoter la LED avec un rythme irrégulier (ex : court, court, long — façon morse). +- Afficher dans le moniteur série un compteur du nombre de clignotements depuis le démarrage. + +## Pour aller plus loin (facultatif) + +Consultez la documentation officielle Espressif sur le cœur Arduino pour ESP32 : elle liste l'ensemble des cartes supportées et des options spécifiques (partitions, PSRAM, etc.) que nous détaillerons au Module 1. diff --git a/modules/01-architecture.qmd b/modules/01-architecture.qmd new file mode 100644 index 0000000..d67f23a --- /dev/null +++ b/modules/01-architecture.qmd @@ -0,0 +1,102 @@ +--- +title: "Module 1 — Découverte du microcontrôleur ESP32-S3" +--- + +## Objectifs du module + +- Comprendre ce qu'est un microcontrôleur et en quoi il diffère d'un ordinateur classique. +- Connaître l'architecture interne de l'ESP32-S3 (cœurs, mémoire, périphériques). +- Identifier les différences clés avec un Arduino Uno/Nano classique. +- Repérer les broches spéciales à éviter (strapping pins) et lire un brochage (pinout). + +## 1. Qu'est-ce qu'un microcontrôleur ? + +Un microcontrôleur est un circuit intégré unique regroupant un processeur, de la mémoire vive (RAM), de la mémoire de programme (Flash) et des périphériques d'entrée/sortie (GPIO, ADC, timers, bus de communication). Contrairement à un ordinateur, il n'exécute généralement qu'un seul programme en boucle, sans système d'exploitation complexe, ce qui garantit un comportement déterministe et une consommation réduite. + +L'ESP32-S3 va plus loin qu'un microcontrôleur classique (type ATmega328 de l'Arduino Uno) en intégrant nativement du Wi-Fi et du Bluetooth Low Energy, ce qui en fait un choix privilégié pour les projets connectés (IoT). + +## 2. Architecture interne de l'ESP32-S3 + +### 2.1 Cœurs de calcul + +- Double cœur Xtensa LX7 cadencé jusqu'à 240 MHz. +- Un cœur peut être dédié à des tâches critiques (ex : communication réseau) pendant que l'autre exécute la logique applicative — via FreeRTOS, présent nativement sous le framework Arduino. + +### 2.2 Mémoire + +- SRAM interne : environ 512 Ko, partagée entre données et instructions. +- Mémoire Flash externe (souvent 8 ou 16 Mo selon la carte) : stocke le programme (sketch) et éventuellement un système de fichiers (SPIFFS/LittleFS). +- PSRAM (RAM externe, optionnelle selon le modèle de carte) : utile pour le traitement d'images ou de gros buffers. + +### 2.3 Connectivité intégrée + +- Wi-Fi 802.11 b/g/n (2,4 GHz). +- Bluetooth 5 LE (Low Energy uniquement — pas de Bluetooth Classic/SPP sur le S3, contrairement à l'ESP32 original). + +### 2.4 Interface USB native + +L'ESP32-S3 dispose d'un contrôleur USB OTG natif, permettant la programmation et la communication série directement via USB, sans puce USB-série intermédiaire (selon la carte). Il peut aussi émuler un périphérique USB (clavier, souris, disque) — nous y reviendrons dans un module avancé. + +## 3. ESP32-S3 vs Arduino Uno : les différences essentielles + +| Caractéristique | Arduino Uno (ATmega328) | ESP32-S3 | +|-------------------|---------------------------|-------------------------------------| +| Cœurs / fréquence | 1 cœur, 16 MHz | 2 cœurs, jusqu'à 240 MHz | +| Tension logique | 5 V | 3,3 V | +| RAM | 2 Ko | \~512 Ko | +| Flash programme | 32 Ko | 8-16 Mo (typique) | +| Wi-Fi / Bluetooth | Non (externe requis) | Intégrés (Wi-Fi + BLE) | +| Broches ADC | 10 bits, 5 entrées | 12 bits, jusqu'à 20 entrées | +| PWM | Limité (Timer matériel) | LEDC — jusqu'à 8 canaux configurables | + +::: {.callout-warning title="Point de vigilance : tension 3,3 V"} +Toutes les broches GPIO de l'ESP32-S3 fonctionnent en logique 3,3 V et ne tolèrent pas 5 V en entrée. Un signal 5 V (capteur, module tiers) doit être abaissé via un diviseur de tension ou un convertisseur de niveau logique avant d'être connecté à une broche. +::: + +## 4. Lire le brochage (pinout) de la carte + +Avant de câbler quoi que ce soit, il est indispensable de repérer sur votre carte : + +- Les broches d'alimentation : 5V (VIN/USB), 3V3, GND. +- Les broches GPIO numérotées (GPIO0 à GPIO21 selon les cartes, tous ne sont pas exposés). +- Les broches ADC (généralement GPIO1 à GPIO10 sur l'unité ADC1). +- La broche pilotant la LED NeoPixel intégrée (souvent GPIO48, à vérifier sur la sérigraphie ou le schéma de votre carte spécifique). + +### Broches à éviter (strapping pins) + +Certaines broches ont un rôle spécial au démarrage (sélection du mode de boot) et peuvent perturber le fonctionnement de la carte si elles sont utilisées comme sorties classiques ou reliées à des composants qui tirent le niveau logique au démarrage : + +- GPIO0 : bouton BOOT — à éviter comme sortie générale. +- GPIO3, GPIO45, GPIO46 : broches de strapping — à utiliser avec prudence, éviter en sortie forte au démarrage. +- GPIO19/GPIO20 : utilisées par l'USB natif sur de nombreuses cartes S3 — à éviter si vous utilisez la connexion USB. + +::: {.callout-tip title="Bonne pratique"} +Gardez toujours sous la main le schéma (pinout diagram) exact de votre référence de carte. Deux cartes vendues comme « ESP32-S3 DevKit » par des fabricants différents peuvent avoir un brochage légèrement différent. +::: + +## 5. Exercice pratique : inventaire de votre carte + +Sans câblage, à l'aide de la documentation de votre carte : + +- Dessinez ou annotez un schéma de votre carte en identifiant : alimentation, GND, GPIO utilisables, broches à éviter, broche de la LED NeoPixel. +- Écrivez un programme qui affiche dans le moniteur série, au démarrage, la fréquence CPU (`getCpuFrequencyMhz()`), la taille de la mémoire Flash (`ESP.getFlashChipSize()`) et la mémoire heap libre (`ESP.getFreeHeap()`). + +```cpp +void setup() { + Serial.begin(115200); + delay(1000); + Serial.printf("Frequence CPU : %d MHz\n", getCpuFrequencyMhz()); + Serial.printf("Taille Flash : %d octets\n", ESP.getFlashChipSize()); + Serial.printf("Heap libre : %d octets\n", ESP.getFreeHeap()); +} + +void loop() { +} +``` + +## Checklist de fin de module + +- [ ] Je sais expliquer la différence entre RAM et Flash sur ce microcontrôleur. +- [ ] Je connais les broches à éviter (strapping pins) sur ma carte. +- [ ] J'ai identifié la broche pilotant la LED NeoPixel intégrée. +- [ ] J'ai exécuté le programme d'inventaire et compris les valeurs affichées. diff --git a/modules/02-gpio-neopixel.qmd b/modules/02-gpio-neopixel.qmd new file mode 100644 index 0000000..14b634a --- /dev/null +++ b/modules/02-gpio-neopixel.qmd @@ -0,0 +1,175 @@ +--- +title: "Module 2 — Entrées/Sorties numériques & LED RGB NeoPixel" +--- + +## Objectifs du module + +- Maîtriser `digitalWrite()` et `digitalRead()` sur l'ESP32-S3. +- Comprendre les résistances de tirage (pull-up / pull-down) et l'anti-rebond logiciel. +- Réaliser un chenillard de LED et une lecture de bouton-poussoir. +- Piloter la LED RGB NeoPixel intégrée à la carte (protocole WS2812, bibliothèque Adafruit_NeoPixel). + +## 1. Rappels : sorties numériques + +Une broche GPIO configurée en sortie (OUTPUT) ne peut prendre que deux états électriques : HIGH (3,3 V) ou LOW (0 V). C'est la base de tout pilotage de LED, relais, transistor de puissance, etc. + +```cpp +#define LED_PIN 4 + +void setup() { + pinMode(LED_PIN, OUTPUT); +} + +void loop() { + digitalWrite(LED_PIN, HIGH); + delay(300); + digitalWrite(LED_PIN, LOW); + delay(300); +} +``` + +## 2. Rappels : entrées numériques et résistances de tirage + +Une entrée numérique non connectée (« flottante ») peut lire un état aléatoire à cause du bruit électrique. Il faut donc fixer son état par défaut avec une résistance de tirage : + +- `INPUT_PULLUP` : la broche est tirée à 3,3 V par défaut (état HIGH) ; le bouton doit relier la broche à GND pour donner un état LOW à l'appui. +- `INPUT_PULLDOWN` : disponible sur l'ESP32-S3 (contrairement à l'AVR classique) — la broche est tirée à 0 V par défaut. + +```cpp +#define BUTTON_PIN 5 + +void setup() { + Serial.begin(115200); + pinMode(BUTTON_PIN, INPUT_PULLUP); +} + +void loop() { + int etat = digitalRead(BUTTON_PIN); + if (etat == LOW) { + Serial.println("Bouton presse"); + } + delay(50); +} +``` + +::: {.callout-note title="Anti-rebond (debounce)"} +Un bouton mécanique génère plusieurs transitions HIGH/LOW parasites en quelques millisecondes lors de l'appui. Un simple `delay(50)` après lecture suffit pour un usage pédagogique ; pour un projet robuste, on mesure le temps écoulé avec `millis()` plutôt que d'utiliser `delay()` (voir Module 6 sur les interruptions et timers). +::: + +## 3. Exercice guidé : chenillard de LED + +Câblez 4 LED (avec résistances de 220 Ω) sur 4 GPIO libres, puis reproduisez un effet de chenillard : + +```cpp +const int leds[] = {4, 5, 6, 7}; +const int nbLeds = 4; + +void setup() { + for (int i = 0; i < nbLeds; i++) { + pinMode(leds[i], OUTPUT); + } +} + +void loop() { + for (int i = 0; i < nbLeds; i++) { + digitalWrite(leds[i], HIGH); + delay(150); + digitalWrite(leds[i], LOW); + } +} +``` + +## 4. La LED RGB NeoPixel intégrée + +Contrairement à une LED classique qui ne prend que deux états (allumé/éteint) ou une intensité en PWM, la LED intégrée sur la plupart des cartes ESP32-S3 DevKit est une LED adressable de type WS2812 (aussi appelée NeoPixel). Elle intègre son propre contrôleur et se pilote avec un protocole série à un seul fil, où chaque LED reçoit une trame de 24 bits (8 bits rouge, 8 bits vert, 8 bits bleu). + +### 4.1 Pourquoi ce n'est pas un simple digitalWrite + +Le protocole WS2812 impose un timing très précis (de l'ordre de la centaine de nanosecondes) pour distinguer un bit 0 d'un bit 1. Le générer « à la main » avec digitalWrite serait peu fiable ; on utilise donc une bibliothèque dédiée qui exploite les ressources matérielles du microcontrôleur pour respecter ce timing. + +### 4.2 Installation de la bibliothèque + +- Dans l'IDE : Croquis \> Inclure une bibliothèque \> Gérer les bibliothèques. +- Rechercher « Adafruit NeoPixel » et installer la dernière version (ainsi que sa dépendance Adafruit BusIO si demandée). + +::: {.callout-note title="Identifier la broche de la LED"} +Sur la plupart des cartes ESP32-S3-DevKitC-1, la LED NeoPixel est reliée au GPIO48 et nécessite d'alimenter une broche annexe (souvent GPIO47 sur certaines révisions) pour l'activer. Vérifiez impérativement le schéma de votre carte : certains modèles utilisent GPIO38 ou un autre GPIO. Le code ci-dessous utilise une constante `NEOPIXEL_PIN` à adapter. +::: + +### 4.3 Premier programme : allumer la LED en rouge + +```cpp +#include + +#define NEOPIXEL_PIN 48 // A adapter selon votre carte +#define NB_PIXELS 1 + +Adafruit_NeoPixel pixels(NB_PIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); + +void setup() { + pixels.begin(); + pixels.setBrightness(50); // Luminosite 0-255, a limiter pour ne pas eblouir + pixels.setPixelColor(0, pixels.Color(255, 0, 0)); // Rouge + pixels.show(); +} + +void loop() { +} +``` + +### 4.4 Exercice : cycle de couleurs et respiration + +Objectif : faire défiler plusieurs couleurs, puis réaliser un effet de « respiration » (variation progressive de la luminosité) sur une couleur fixe. + +```cpp +#include + +#define NEOPIXEL_PIN 48 +Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); + +void setup() { + pixel.begin(); + pixel.setBrightness(80); +} + +void loop() { + // Cycle de couleurs + pixel.setPixelColor(0, pixel.Color(255, 0, 0)); pixel.show(); delay(400); + pixel.setPixelColor(0, pixel.Color(0, 255, 0)); pixel.show(); delay(400); + pixel.setPixelColor(0, pixel.Color(0, 0, 255)); pixel.show(); delay(400); + + // Effet respiration en bleu + for (int b = 0; b <= 255; b += 5) { + pixel.setBrightness(b); + pixel.setPixelColor(0, pixel.Color(0, 0, 255)); + pixel.show(); + delay(15); + } + for (int b = 255; b >= 0; b -= 5) { + pixel.setBrightness(b); + pixel.setPixelColor(0, pixel.Color(0, 0, 255)); + pixel.show(); + delay(15); + } +} +``` + +## 5. Exercice final : bouton + NeoPixel + +Combinez les notions du module : à chaque appui sur un bouton-poussoir (avec `INPUT_PULLUP` et anti-rebond), la LED NeoPixel doit changer de couleur en suivant un cycle défini (rouge → vert → bleu → blanc → éteint → rouge...). + +| Étape | Comportement attendu | +|---------|------------------------------------| +| Démarrage | LED éteinte | +| 1er appui | LED rouge | +| 2e appui | LED verte | +| 3e appui | LED bleue | +| 4e appui | LED blanche | +| 5e appui | Retour à éteint, le cycle recommence | + +## Checklist de fin de module + +- [ ] Je sais configurer et lire un bouton avec `INPUT_PULLUP`. +- [ ] Je comprends pourquoi un debounce est nécessaire. +- [ ] J'ai identifié la broche exacte de la LED NeoPixel sur ma carte. +- [ ] J'ai réalisé l'exercice combinant bouton et changement de couleur. diff --git a/modules/03-pwm-adc.qmd b/modules/03-pwm-adc.qmd index 48a453f..7713c17 100644 --- a/modules/03-pwm-adc.qmd +++ b/modules/03-pwm-adc.qmd @@ -80,7 +80,7 @@ L'ADC convertit une tension continue (0 à 3,3 V) en une valeur numérique. L'ES ![Conversion analogique-numérique puis mise à l'échelle avec map()](../schemas/svg/m03-adc-quantification.svg){#fig-m03-adc-quantification} | Caractéristique | Valeur | -|---|---| +|-----------------------------------|----------------------------------------| | Résolution native | 12 bits (0 à 4095) | | Plage de tension | 0 à 3,3 V (selon atténuation configurée) | | Unité ADC utilisable en Wi-Fi actif | ADC1 uniquement (ADC2 partagé avec le Wi-Fi) | diff --git a/modules/04-serie-debug.qmd b/modules/04-serie-debug.qmd new file mode 100644 index 0000000..c2959ce --- /dev/null +++ b/modules/04-serie-debug.qmd @@ -0,0 +1,155 @@ +--- +title: "Module 4 — Communication série & débogage" +--- + +## Objectifs du module + +- Comprendre le fonctionnement du bus UART et son rôle central dans le débogage. +- Distinguer les différents ports série disponibles sur l'ESP32-S3. +- Utiliser efficacement le moniteur série et les fonctions d'affichage formaté. +- Construire une petite console de commandes interactive. + +## 1. Rappel : qu'est-ce que l'UART ? + +L'UART (Universal Asynchronous Receiver-Transmitter) est un protocole de communication série point à point utilisant deux fils : TX (transmission) et RX (réception), sans horloge partagée — les deux extrémités doivent donc être configurées à la même vitesse (baud rate) pour interpréter correctement les bits reçus. + +Sur l'ESP32-S3, la liaison série vers l'ordinateur (moniteur série de l'IDE) transite le plus souvent directement par le port USB natif du microcontrôleur (USB CDC), et non par un UART matériel classique relié à une puce USB-série externe — d'où l'importance de l'option « USB CDC On Boot » vue au Module 0. + +## 2. Les ports série disponibles + +L'ESP32-S3 dispose de plusieurs contrôleurs UART matériels, utilisables simultanément pour des usages différents (ex : un port pour le debug, un autre pour dialoguer avec un module GPS ou un lecteur RFID). + +| Objet | Usage typique | +|---------|----------------------------------------| +| Serial | Console USB (moniteur série / debug), via USB CDC sur l'ESP32-S3 | +| Serial1 | UART matériel n°1, broches à réassigner explicitement | +| Serial2 | UART matériel n°2, broches à réassigner explicitement | + +::: {.callout-note title="Réassignation des broches UART"} +Sur l'ESP32-S3, les broches des UART matériels ne sont pas fixes : on les définit avec Serial1.begin(baud, config, rxPin, txPin). Vérifiez que les broches choisies ne font pas partie des broches à éviter identifiées au Module 1. + +// Exemple : Serial2 sur les broches GPIO17 (RX) et GPIO18 (TX) + +#define RX2 17 + +#define TX2 18 + +void `setup()` { + +`Serial.begin(115200)`; // console USB + +Serial2.begin(9600, `SERIAL_8N1`, RX2, TX2); // module externe + +} + +void `loop()` { + +if (`Serial2.available()`) { + +String recu = `Serial2.readStringUntil('\n')`; + +Serial.print("Recu du module: "); + +`Serial.println(recu)`; + +} + +} +::: + +## 3. Bien utiliser le moniteur série + +### 3.1 Fonctions d'affichage + +| Fonction | Rôle | +|-----------------------|----------------------------------------| +| `Serial.print(x)` | Affiche x sans retour à la ligne | +| `Serial.println(x)` | Affiche x avec un retour à la ligne | +| Serial.printf(fmt, ...) | Affichage formaté façon C (%d, %s, %f, %.2f...) | + +```cpp +int temperature = 24; +float tension = 3.298; + +Serial.printf("Temperature: %d C, Tension: %.2f V\n", temperature, tension); +``` + +::: {.callout-tip title="Bonne pratique de debug"} +Préférez `Serial.printf()` à la concaténation de multiples `Serial.print()` : le code est plus lisible et plus facile à maintenir, surtout lorsqu'on affiche plusieurs variables à la fois. +::: + +## 4. Lire des données envoyées depuis le moniteur série + +Le moniteur série permet aussi d'envoyer du texte vers la carte, ce qui est très utile pour créer des interfaces de test simples (changer un paramètre sans reflasher le programme). + +```cpp +void setup() { + Serial.begin(115200); + Serial.println("Tapez une commande puis Entree"); +} + +void loop() { + if (Serial.available()) { + String commande = Serial.readStringUntil('\n'); + commande.trim(); // supprime espaces/retours de fin + Serial.print("Commande recue: "); + Serial.println(commande); + } +} +``` + +## 5. Exercice pratique : mini console de commandes + +En vous appuyant sur la LED NeoPixel du Module 2, développez une petite console pilotée par le moniteur série : + +- La commande « rouge » allume la LED en rouge. +- La commande « vert » l'allume en vert. +- La commande « bleu » l'allume en bleu. +- La commande « off » l'éteint. +- Toute commande inconnue affiche un message d'erreur explicite. + +```cpp +#include +#define NEOPIXEL_PIN 48 +Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); + +void setup() { + Serial.begin(115200); + pixel.begin(); + Serial.println("Commandes disponibles: rouge, vert, bleu, off"); +} + +void loop() { + if (Serial.available()) { + String cmd = Serial.readStringUntil('\n'); + cmd.trim(); + cmd.toLowerCase(); + + if (cmd == "rouge") { + pixel.setPixelColor(0, pixel.Color(255, 0, 0)); + } else if (cmd == "vert") { + pixel.setPixelColor(0, pixel.Color(0, 255, 0)); + } else if (cmd == "bleu") { + pixel.setPixelColor(0, pixel.Color(0, 0, 255)); + } else if (cmd == "off") { + pixel.setPixelColor(0, pixel.Color(0, 0, 0)); + } else { + Serial.println("Commande inconnue."); + return; + } + pixel.show(); + Serial.println("OK"); + } +} +``` + +## 6. Pour aller plus loin (facultatif) + +Ajoutez une commande « couleur R G B » qui accepte trois nombres séparés par des espaces (ex : couleur 128 0 255) en utilisant les fonctions `indexOf()` et `substring()` ou la fonction `sscanf()` pour extraire les valeurs de la chaîne reçue. + +## Checklist de fin de module + +- [ ] Je comprends la différence entre Serial, Serial1 et Serial2. +- [ ] Je sais réassigner les broches RX/TX d'un UART matériel. +- [ ] Je maîtrise `Serial.printf()` pour un affichage de debug formaté. +- [ ] J'ai réalisé la mini console de commandes pilotant la LED NeoPixel. diff --git a/modules/05-i2c-spi.qmd b/modules/05-i2c-spi.qmd new file mode 100644 index 0000000..fb1ff90 --- /dev/null +++ b/modules/05-i2c-spi.qmd @@ -0,0 +1,177 @@ +--- +title: "Module 5 — Bus I2C et SPI" +--- + +## Objectifs du module + +- Comprendre les principes des bus I2C et SPI et leurs différences. +- Câbler et adresser un périphérique I2C (scanner de bus, résolution de conflits d'adresse). +- Afficher du texte et des formes sur un écran OLED SSD1306 (I2C). +- Lire les données d'un capteur de température/humidité BME280 (I2C). + +## 1. Pourquoi un bus de communication ? + +Les broches GPIO génériques permettent de dialoguer avec un seul composant à la fois, en définissant vous-même le protocole. Pour standardiser les échanges avec des composants variés (écrans, capteurs, mémoires), l'industrie utilise des bus normalisés : I2C et SPI sont les deux plus répandus dans l'écosystème Arduino/ESP32. + +## 2. Le bus I2C + +### 2.1 Principe + +I2C (Inter-Integrated Circuit) utilise seulement deux fils partagés par tous les périphériques du bus : + +- SDA (Serial Data) : ligne de données. +- SCL (Serial Clock) : ligne d'horloge, générée par le maître (l'ESP32-S3 dans notre cas). + +Chaque périphérique possède une adresse unique (7 bits, soit 128 adresses possibles) qui permet au maître de s'adresser spécifiquement à lui sur le bus partagé. + +### 2.2 Broches I2C par défaut sur ESP32-S3 + +Le framework Arduino-ESP32 définit par défaut SDA sur GPIO8 et SCL sur GPIO9 (à vérifier selon votre carte), mais ces broches peuvent être réassignées via Wire.begin(sda, scl). + +```cpp +#include + +void setup() { + Wire.begin(8, 9); // SDA, SCL — a adapter selon votre carte +} +``` + +## 3. Scanner de bus I2C + +Avant de câbler un module, il est très utile de vérifier qu'il est bien détecté et de connaître son adresse exacte : + +```cpp +#include + +void setup() { + Wire.begin(8, 9); + Serial.begin(115200); + delay(500); + Serial.println("Scan du bus I2C..."); + + for (byte addr = 1; addr < 127; addr++) { + Wire.beginTransmission(addr); + byte erreur = Wire.endTransmission(); + if (erreur == 0) { + Serial.printf("Peripherique trouve a l'adresse 0x%02X\n", addr); + } + } + Serial.println("Scan termine."); +} + +void loop() { +} +``` + +::: {.callout-note title="Conflit d'adresse"} +Si deux modules identiques (deux écrans OLED par exemple) doivent cohabiter sur le même bus, ils doivent avoir des adresses différentes. Certains modules disposent de pastilles de soudure (solder jumpers) permettant de changer leur adresse d'usine. +::: + +## 4. Exercice : afficheur OLED SSD1306 + +### 4.1 Installation des bibliothèques + +- Adafruit GFX Library (moteur graphique générique). +- Adafruit SSD1306 (pilote spécifique à l'écran). + +### 4.2 Câblage + +| Broche écran | Broche ESP32-S3 | +|----------------|-----------------------------| +| VCC | 3V3 | +| GND | GND | +| SDA | GPIO8 (ou broche SDA choisie) | +| SCL | GPIO9 (ou broche SCL choisie) | + +### 4.3 Premier affichage + +```cpp +#include +#include +#include + +#define SCREEN_WIDTH 128 +#define SCREEN_HEIGHT 64 +#define OLED_ADDR 0x3C // Adresse trouvee avec le scanner I2C + +Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); + +void setup() { + Wire.begin(8, 9); + if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) { + Serial.println("Ecran non detecte !"); + while (true); + } + display.clearDisplay(); + display.setTextSize(2); + display.setTextColor(SSD1306_WHITE); + display.setCursor(0, 0); + display.println("Bonjour !"); + display.display(); +} + +void loop() { +} +``` + +## 5. Exercice : capteur de température/humidité BME280 + +Le BME280 est un capteur environnemental (température, humidité, pression) communiquant en I2C, très utilisé dans les projets de station météo. + +### 5.1 Installation de la bibliothèque + +Installer « Adafruit BME280 Library » depuis le gestionnaire de bibliothèques. + +### 5.2 Lecture des mesures + +```cpp +#include +#include + +Adafruit_BME280 bme; + +void setup() { + Serial.begin(115200); + Wire.begin(8, 9); + if (!bme.begin(0x76)) { // ou 0x77 selon le module + Serial.println("BME280 non detecte !"); + while (true); + } +} + +void loop() { + float temperature = bme.readTemperature(); + float humidite = bme.readHumidity(); + float pression = bme.readPressure() / 100.0F; // hPa + + Serial.printf("T: %.1f C H: %.1f %% P: %.1f hPa\n", temperature, humidite, pression); + delay(2000); +} +``` + +## 6. Exercice combiné : mini station météo + +Combinez écran OLED et capteur BME280 pour afficher en temps réel la température et l'humidité, avec rafraîchissement toutes les 2 secondes. Ajoutez un indicateur visuel sur la LED NeoPixel : bleu si température \< 18°C, vert entre 18 et 25°C, rouge au-delà. + +## 7. Le bus SPI : présentation + +SPI (Serial Peripheral Interface) est plus rapide que l'I2C mais utilise davantage de fils : MOSI (données maître→esclave), MISO (esclave→maître), SCK (horloge) et une ligne CS (Chip Select) dédiée par périphérique. Il est privilégié pour les composants nécessitant un débit élevé (écrans TFT couleur, cartes SD, certains modules radio). + +| Critère | I2C | SPI | +|---------------|-----------------------|--------------------------------| +| Nombre de fils | 2 (partagés) | 4 (+1 CS par périphérique) | +| Vitesse typique | 100 kHz - 1 MHz | Plusieurs MHz à dizaines de MHz | +| Adressage | Adresse logicielle | Ligne CS physique dédiée | +| Usage typique | Capteurs, petits écrans | Écrans rapides, cartes SD, radio | + +::: {.callout-note title="Approfondissement SPI"} +Le câblage et l'utilisation détaillée du SPI (ex : écran TFT, carte SD) seront pratiqués dans un module dédié aux projets avancés, en fonction du matériel disponible pour la formation. +::: + +## Checklist de fin de module + +- [ ] J'ai exécuté le scanner I2C et identifié les adresses de mes modules. +- [ ] J'ai affiché du texte sur l'écran OLED. +- [ ] J'ai lu température et humidité depuis le BME280. +- [ ] J'ai réalisé la mini station météo combinant écran, capteur et LED NeoPixel. +- [ ] Je sais expliquer la différence entre I2C et SPI. diff --git a/modules/06-interruptions-timers.qmd b/modules/06-interruptions-timers.qmd new file mode 100644 index 0000000..fbd7c81 --- /dev/null +++ b/modules/06-interruptions-timers.qmd @@ -0,0 +1,167 @@ +--- +title: "Module 6 — Interruptions matérielles & Timers" +--- + +## Objectifs du module + +- Comprendre les limites de `delay()` et de la boucle `loop()` classique. +- Utiliser `millis()` pour gérer plusieurs tâches périodiques sans bloquer le programme. +- Mettre en œuvre une interruption matérielle avec `attachInterrupt()`. +- Comprendre le rôle de `IRAM_ATTR` et les bonnes pratiques dans une routine d'interruption (ISR). + +## 1. Le problème de `delay()` + +La fonction `delay()` bloque totalement l'exécution du programme pendant la durée spécifiée : aucune autre instruction (lecture de bouton, mise à jour d'écran, communication réseau) ne peut s'exécuter pendant ce temps. Pour un programme qui ne fait qu'une seule chose, ce n'est pas gênant ; mais dès qu'on veut gérer plusieurs comportements simultanés (ex : clignoter une LED tout en surveillant un bouton), `delay()` devient un frein majeur. + +## 2. La technique du « blink sans delay » avec `millis()` + +`millis()` renvoie le nombre de millisecondes écoulées depuis le démarrage du programme. En comparant cette valeur à un dernier instant mémorisé, on peut exécuter une action périodique sans jamais bloquer la boucle `loop()`. + +```cpp +#define LED_PIN 4 +unsigned long dernierChangement = 0; +const unsigned long intervalle = 500; // ms +bool etatLed = false; + +void setup() { + pinMode(LED_PIN, OUTPUT); +} + +void loop() { + unsigned long maintenant = millis(); + + if (maintenant - dernierChangement >= intervalle) { + dernierChangement = maintenant; + etatLed = !etatLed; + digitalWrite(LED_PIN, etatLed); + } + + // Ici, on pourrait ajouter d'autres taches (lecture bouton, etc.) + // sans que le clignotement ne soit bloque. +} +``` + +::: {.callout-note title="Pourquoi unsigned long ?"} +`millis()` renvoie une valeur qui finit par déborder (« overflow ») après environ 49 jours de fonctionnement continu. Utiliser la soustraction (maintenant - dernierChangement) plutôt qu'une comparaison directe des deux valeurs absolues gère correctement ce débordement grâce à l'arithmétique non signée. +::: + +## 3. Exercice : plusieurs tâches périodiques indépendantes + +Reprenez la logique de « blink sans delay » pour gérer simultanément trois comportements à des fréquences différentes : clignotement d'une LED classique toutes les 300 ms, cycle de couleur de la LED NeoPixel toutes les 1000 ms, et affichage d'un message de debug toutes les 5000 ms. + +## 4. Les interruptions matérielles + +### 4.1 Principe + +Une interruption permet au microcontrôleur de réagir instantanément à un évènement matériel (front montant ou descendant sur une broche), en suspendant momentanément l'exécution de la boucle principale pour exécuter une fonction dédiée, appelée ISR (Interrupt Service Routine). C'est indispensable pour ne manquer aucun évènement rapide, comme une impulsion d'encodeur rotatif ou un appui bref sur un bouton. + +### 4.2 `attachInterrupt()` + +```cpp +#define BUTTON_PIN 5 + +volatile bool interruptionDetectee = false; + +void IRAM_ATTR gererInterruption() { + interruptionDetectee = true; +} + +void setup() { + Serial.begin(115200); + pinMode(BUTTON_PIN, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), gererInterruption, FALLING); +} + +void loop() { + if (interruptionDetectee) { + interruptionDetectee = false; + Serial.println("Interruption traitee dans loop()"); + } +} +``` + +::: {.callout-note title="Règles d'or d'une ISR"} +Une routine d'interruption doit être aussi courte et rapide que possible : pas de `Serial.print()`, pas de `delay()`, pas d'allocation mémoire. La bonne pratique consiste à se contenter de modifier une variable volatile (comme ci-dessus) et à traiter l'évènement dans `loop()`. Le mot-clé `IRAM_ATTR` indique que le code de la fonction doit être placé en RAM interne pour un temps d'exécution garanti, même si le cache Flash est momentanément indisponible. +::: + +### 4.3 Les modes de déclenchement + +| Mode | Déclenchement | +|----------|----------------------------------------| +| RISING | Sur front montant (passage de LOW à HIGH) | +| FALLING | Sur front descendant (passage de HIGH à LOW) | +| CHANGE | Sur tout changement d'état | +| LOW / HIGH | Tant que la broche reste dans cet état (peu utilisé) | + +## 5. Exercice : compteur d'impulsions (encodeur rotatif) + +Un encodeur rotatif génère des impulsions sur deux broches (souvent nommées CLK et DT) permettant de détecter le sens de rotation. Câblez un encodeur rotatif et comptez le nombre de crans parcourus à l'aide d'une interruption sur la broche CLK. + +```cpp +#define CLK_PIN 6 +#define DT_PIN 7 + +volatile int compteur = 0; + +void IRAM_ATTR gererRotation() { + if (digitalRead(DT_PIN) == HIGH) { + compteur++; + } else { + compteur--; + } +} + +void setup() { + Serial.begin(115200); + pinMode(CLK_PIN, INPUT_PULLUP); + pinMode(DT_PIN, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(CLK_PIN), gererRotation, FALLING); +} + +void loop() { + static int dernierAffiche = 0; + if (compteur != dernierAffiche) { + dernierAffiche = compteur; + Serial.printf("Position: %d\n", compteur); + } +} +``` + +## 6. Les timers matériels + +En complément des interruptions déclenchées par un évènement externe, l'ESP32-S3 dispose de timers matériels internes capables de générer une interruption à intervalle régulier, indépendamment de la boucle `loop()`. Utile pour des tâches critiques en temps (échantillonnage régulier, watchdog applicatif). + +```cpp +hw_timer_t *minuteur = NULL; +volatile bool declenche = false; + +void IRAM_ATTR onTimer() { + declenche = true; +} + +void setup() { + Serial.begin(115200); + minuteur = timerBegin(1000000); // 1 MHz -> tick = 1 microseconde + timerAttachInterrupt(minuteur, &onTimer); + timerAlarm(minuteur, 1000000, true, 0); // declenchement toutes les 1 000 000 us = 1 s +} + +void loop() { + if (declenche) { + declenche = false; + Serial.println("Tick timer materiel (1s)"); + } +} +``` + +::: {.callout-note title="Version de l'API timer"} +Comme pour LEDC, l'API des timers matériels a évolué entre les versions du core Arduino-ESP32 (l'ancienne API utilisait timerBegin(numero, diviseur, compteMontant)). Vérifiez la signature correspondant à votre version installée si le code ne compile pas. +::: + +## Checklist de fin de module + +- [ ] Je sais remplacer un `delay()` par une gestion à base de `millis()`. +- [ ] Je sais faire cohabiter plusieurs tâches périodiques indépendantes dans `loop()`. +- [ ] Je sais déclencher une interruption avec `attachInterrupt()` et écrire une ISR minimale et sûre. +- [ ] J'ai réalisé le compteur d'impulsions avec un encodeur rotatif. +- [ ] Je comprends le rôle d'un timer matériel par rapport à une interruption externe. diff --git a/modules/07-wifi.qmd b/modules/07-wifi.qmd new file mode 100644 index 0000000..93d5831 --- /dev/null +++ b/modules/07-wifi.qmd @@ -0,0 +1,157 @@ +--- +title: "Module 7 — Wi-Fi : station, point d'accès et client HTTP" +--- + +## Objectifs du module + +- Comprendre les deux modes de fonctionnement Wi-Fi de l'ESP32-S3 : station (STA) et point d'accès (AP). +- Connecter la carte à un réseau Wi-Fi existant. +- Créer son propre point d'accès Wi-Fi depuis la carte. +- Réaliser une requête HTTP GET vers une API externe et exploiter la réponse JSON. + +## 1. Les modes Wi-Fi de l'ESP32-S3 + +| Mode | Rôle | Usage typique | +|-------------------------|----------------------------------------|----------------------------------------| +| `WIFI_STA` (Station) | La carte se connecte à un routeur/box existant | Envoyer des données sur Internet, rejoindre le réseau local | +| `WIFI_AP` (Point d'accès) | La carte crée son propre réseau Wi-Fi | Configuration sans routeur, projet autonome | +| `WIFI_AP_STA` | Les deux simultanément | Portail de configuration puis bascule en client | + +## 2. Mode station : se connecter à un réseau existant + +```cpp +#include + +const char* ssid = "NomDuReseau"; +const char* motDePasse = "MotDePasse"; + +void setup() { + Serial.begin(115200); + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, motDePasse); + + Serial.print("Connexion en cours"); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(); + Serial.print("Connecte ! Adresse IP: "); + Serial.println(WiFi.localIP()); +} + +void loop() { +} +``` + +::: {.callout-important title="Sécurité : ne jamais versionner ses identifiants"} +Évitez d'écrire en clair vos identifiants Wi-Fi dans un fichier destiné à être partagé ou publié (dépôt Git). Une bonne pratique consiste à les isoler dans un fichier séparé non partagé (ex : secrets.h), ou à les saisir via le moniteur série au premier démarrage. +::: + +## 3. Mode point d'accès : créer son propre réseau + +```cpp +#include + +const char* ssidAP = "ESP32-Formation"; +const char* motDePasseAP = "formation123"; // 8 caracteres minimum + +void setup() { + Serial.begin(115200); + WiFi.mode(WIFI_AP); + WiFi.softAP(ssidAP, motDePasseAP); + + Serial.print("Point d'acces cree. IP: "); + Serial.println(WiFi.softAPIP()); // generalement 192.168.4.1 +} + +void loop() { +} +``` + +## 4. Client HTTP : interroger une API externe + +Une fois connectée en mode station, la carte peut effectuer des requêtes HTTP vers des services web, par exemple pour récupérer la météo actuelle. + +### 4.1 Bibliothèque nécessaire + +HTTPClient est incluse nativement dans le core Arduino-ESP32. Pour analyser une réponse JSON, installez la bibliothèque « ArduinoJson » (Benoit Blanchon) depuis le gestionnaire de bibliothèques. + +### 4.2 Requête GET simple + +```cpp +#include +#include + +void setup() { + Serial.begin(115200); + WiFi.begin("NomDuReseau", "MotDePasse"); + while (WiFi.status() != WL_CONNECTED) { delay(500); } + + HTTPClient http; + http.begin("https://api.exemple.com/donnees"); + int codeReponse = http.GET(); + + if (codeReponse == 200) { + String reponse = http.getString(); + Serial.println(reponse); + } else { + Serial.printf("Erreur HTTP: %d\n", codeReponse); + } + http.end(); +} + +void loop() { +} +``` + +## 5. Exercice : afficher la météo en temps réel + +Combinez cette section avec le Module 5 (écran OLED) : interrogez une API météo publique (par exemple Open-Meteo, qui ne nécessite pas de clé d'API) et affichez la température actuelle sur l'écran OLED, avec rafraîchissement toutes les 10 minutes. + +```cpp +#include +#include +#include + +void setup() { + Serial.begin(115200); + WiFi.begin("NomDuReseau", "MotDePasse"); + while (WiFi.status() != WL_CONNECTED) { delay(500); } + + HTTPClient http; + // Exemple : latitude/longitude de Paris + http.begin("https://api.open-meteo.com/v1/forecast?latitude=48.85&longitude=2.35¤t_weather=true"); + int code = http.GET(); + + if (code == 200) { + String payload = http.getString(); + JsonDocument doc; + deserializeJson(doc, payload); + float temp = doc["current_weather"]["temperature"]; + Serial.printf("Temperature actuelle: %.1f C\n", temp); + } + http.end(); +} + +void loop() { +} +``` + +::: {.callout-important title="Rappel important : ADC2 et Wi-Fi"} +Comme vu au Module 3, dès que le Wi-Fi est actif, évitez toute lecture analogique sur les broches de l'ADC2 : privilégiez systématiquement l'ADC1 dans vos projets connectés. +::: + +## 6. Indicateur visuel de connexion avec la LED NeoPixel + +Ajoutez un indicateur d'état de connexion sur la LED NeoPixel intégrée : orange clignotant pendant la tentative de connexion, vert fixe une fois connecté, rouge fixe en cas d'échec après un délai (par exemple 10 secondes de tentative). + +## Checklist de fin de module + +- [ ] Je sais connecter la carte à un réseau Wi-Fi existant (mode STA). +- [ ] Je sais créer un point d'accès Wi-Fi autonome (mode AP). +- [ ] Je sais effectuer une requête HTTP GET et lire le code de réponse. +- [ ] Je sais extraire une valeur d'une réponse JSON avec ArduinoJson. +- [ ] J'ai réalisé l'affichage météo en temps réel sur l'écran OLED. +- [ ] J'ai ajouté l'indicateur de connexion sur la LED NeoPixel. diff --git a/modules/08-serveurweb.qmd b/modules/08-serveurweb.qmd new file mode 100644 index 0000000..ad5f7f7 --- /dev/null +++ b/modules/08-serveurweb.qmd @@ -0,0 +1,125 @@ +--- +title: "Module 8 — Serveur Web embarqué" +--- + +## Objectifs du module + +- Comprendre le rôle d'un serveur web embarqué et son intérêt pour piloter une carte sans application dédiée. +- Créer un serveur HTTP avec WebServer.h et définir des routes. +- Construire une page HTML de contrôle simple. +- Découvrir le WebSocket pour une communication en temps réel bidirectionnelle. + +## 1. Pourquoi un serveur web embarqué ? + +Plutôt que de développer une application mobile dédiée, l'ESP32-S3 peut lui-même héberger une page web accessible depuis n'importe quel navigateur (smartphone, ordinateur) connecté au même réseau. C'est une solution rapide et universelle pour créer une interface de contrôle ou de supervision d'un projet. + +## 2. Serveur web basique avec WebServer.h + +La bibliothèque WebServer (incluse dans le core Arduino-ESP32) permet de définir des routes (URL) et la réponse associée à chacune. + +```cpp +#include +#include + +const char* ssid = "NomDuReseau"; +const char* motDePasse = "MotDePasse"; + +WebServer serveur(80); + +void gererRacine() { + serveur.send(200, "text/plain", "Serveur ESP32-S3 operationnel !"); +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, motDePasse); + while (WiFi.status() != WL_CONNECTED) { delay(500); } + + Serial.print("Serveur accessible sur : http://"); + Serial.println(WiFi.localIP()); + + serveur.on("/", gererRacine); + serveur.begin(); +} + +void loop() { + serveur.handleClient(); // A appeler en permanence, sans delay() bloquant +} +``` + +::: {.callout-note title="handleClient() et delay()"} +`serveur.handleClient()` doit être appelée le plus souvent possible dans `loop()`. Évitez tout `delay()` long dans votre boucle principale, sous peine de rendre le serveur peu réactif — reprenez la technique `millis()` vue au Module 6 si vous devez gérer d'autres tâches périodiques en parallèle. +::: + +## 3. Page HTML de contrôle de la LED NeoPixel + +Construisons une page avec des boutons permettant de changer la couleur de la LED NeoPixel intégrée, directement depuis un navigateur. + +```cpp +#include +#include +#include + +#define NEOPIXEL_PIN 48 +Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); +WebServer serveur(80); + +const char pageHTML[] PROGMEM = R"rawliteral( + +Controle LED ESP32-S3 + +

Controle de la LED NeoPixel

+ + + + + +)rawliteral"; + +void changerCouleur(int r, int g, int b) { + pixel.setPixelColor(0, pixel.Color(r, g, b)); + pixel.show(); +} + +void setup() { + pixel.begin(); + WiFi.begin("NomDuReseau", "MotDePasse"); + while (WiFi.status() != WL_CONNECTED) { delay(500); } + + serveur.on("/", []() { serveur.send(200, "text/html", pageHTML); }); + serveur.on("/rouge", []() { changerCouleur(255,0,0); serveur.send(200,"text/html",pageHTML); }); + serveur.on("/vert", []() { changerCouleur(0,255,0); serveur.send(200,"text/html",pageHTML); }); + serveur.on("/bleu", []() { changerCouleur(0,0,255); serveur.send(200,"text/html",pageHTML); }); + serveur.on("/off", []() { changerCouleur(0,0,0); serveur.send(200,"text/html",pageHTML); }); + serveur.begin(); +} + +void loop() { + serveur.handleClient(); +} +``` + +::: {.callout-note title="PROGMEM"} +Le mot-clé PROGMEM place la chaîne de caractères HTML directement en mémoire Flash plutôt qu'en RAM, économisant une ressource précieuse lorsque la page grandit en taille. +::: + +## 4. Introduction au WebSocket + +Le modèle utilisé ci-dessus (rechargement de page à chaque clic) fonctionne mais reste rudimentaire. Le WebSocket établit une connexion persistante entre le navigateur et la carte, permettant un échange de données en temps réel sans recharger la page — idéal pour afficher en continu une mesure de capteur ou réagir instantanément à une action utilisateur. + +Cette technique nécessite la bibliothèque tierce « ESPAsyncWebServer » couplée à « AsyncTCP », plus avancée que WebServer.h. Elle sera abordée en détail dans le cadre du projet final (Module 12) si le projet choisi le nécessite (ex : dashboard de supervision en direct). + +## 5. Exercice : dashboard de supervision + +En combinant les modules précédents, créez une page web affichant : + +- La température et l'humidité actuelles (capteur BME280 du Module 5). +- Un bouton pour changer la couleur de la LED NeoPixel. +- L'adresse IP et le temps de fonctionnement (uptime, via `millis()`) de la carte. + +## Checklist de fin de module + +- [ ] Je sais créer un serveur web basique avec des routes définies. +- [ ] Je sais renvoyer une page HTML complète avec des boutons d'action. +- [ ] Je comprends la différence entre le modèle HTTP classique et le WebSocket. +- [ ] J'ai réalisé le dashboard de supervision combinant capteur, LED et informations système. diff --git a/modules/09-ble.qmd b/modules/09-ble.qmd new file mode 100644 index 0000000..35a448d --- /dev/null +++ b/modules/09-ble.qmd @@ -0,0 +1,161 @@ +--- +title: "Module 9 — Bluetooth Low Energy (BLE)" +--- + +## Objectifs du module + +- Comprendre les concepts fondamentaux du BLE : serveur, service, caractéristique. +- Créer un serveur BLE sur l'ESP32-S3 exposant une caractéristique lisible et modifiable. +- Piloter la LED NeoPixel depuis une application smartphone générique (ex : nRF Connect). +- Comprendre les notifications BLE pour l'envoi de données en temps réel. + +## 1. BLE sur l'ESP32-S3 : ce qu'il faut savoir + +::: {.callout-warning title="Pas de Bluetooth Classic sur l'ESP32-S3"} +Contrairement à l'ESP32 « original », l'ESP32-S3 ne supporte pas le Bluetooth Classic (profil SPP notamment). Seul le Bluetooth Low Energy (BLE) est disponible. Cela signifie qu'on ne peut pas l'apparier comme un simple périphérique série Bluetooth classique : toute communication passe par le modèle GATT (services et caractéristiques) décrit dans ce module. +::: + +## 2. Vocabulaire du BLE (modèle GATT) + +| Terme | Définition | +|---------------|----------------------------------------| +| Serveur BLE | L'appareil qui expose des données (ici, l'ESP32-S3) | +| Client BLE | L'appareil qui se connecte et consulte les données (ex : smartphone) | +| Service | Un regroupement logique de fonctionnalités, identifié par un UUID unique | +| Caractéristique | Une donnée précise à l'intérieur d'un service (ex : une couleur, une température), également identifiée par un UUID | +| Notification | Mécanisme permettant au serveur d'envoyer une mise à jour au client sans que celui-ci ait à demander (poll) | + +::: {.callout-note title="Qu'est-ce qu'un UUID ?"} +Un UUID (Universally Unique Identifier) est un identifiant sur 128 bits garantissant qu'aucun autre service ou caractéristique dans le monde n'utilisera accidentellement le même identifiant. Pour vos projets personnels, générez vos propres UUID aléatoires via un générateur en ligne plutôt que de réutiliser des exemples trouvés sur Internet. +::: + +## 3. Créer un serveur BLE minimal + +La bibliothèque BLE est incluse nativement dans le core Arduino-ESP32 (aucune installation nécessaire). + +```cpp +#include +#include +#include +#include + +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + +BLECharacteristic *caracteristique; + +void setup() { + Serial.begin(115200); + BLEDevice::init("ESP32-S3-Formation"); + BLEServer *serveur = BLEDevice::createServer(); + BLEService *service = serveur->createService(SERVICE_UUID); + + caracteristique = service->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE + ); + caracteristique->setValue("En attente..."); + + service->start(); + BLEDevice::getAdvertising()->start(); + Serial.println("Serveur BLE demarre, en attente de connexion..."); +} + +void loop() { +} +``` + +## 4. Réagir à l'écriture d'une valeur (callback) + +Pour piloter la LED NeoPixel depuis un smartphone, il faut détecter quand le client BLE écrit une nouvelle valeur dans la caractéristique. + +```cpp +#include +#include +#include +#include + +#define NEOPIXEL_PIN 48 +#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" +#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" + +Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); + +class MonCallback : public BLECharacteristicCallbacks { + void onWrite(BLECharacteristic *car) override { + String valeur = car->getValue(); + Serial.print("Valeur recue: "); + Serial.println(valeur); + + if (valeur == "rouge") pixel.setPixelColor(0, pixel.Color(255,0,0)); + else if (valeur == "vert") pixel.setPixelColor(0, pixel.Color(0,255,0)); + else if (valeur == "bleu") pixel.setPixelColor(0, pixel.Color(0,0,255)); + else if (valeur == "off") pixel.setPixelColor(0, pixel.Color(0,0,0)); + pixel.show(); + } +}; + +void setup() { + Serial.begin(115200); + pixel.begin(); + + BLEDevice::init("ESP32-S3-Formation"); + BLEServer *serveur = BLEDevice::createServer(); + BLEService *service = serveur->createService(SERVICE_UUID); + + BLECharacteristic *car = service->createCharacteristic( + CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE + ); + car->setCallbacks(new MonCallback()); + car->setValue("off"); + + service->start(); + BLEDevice::getAdvertising()->start(); + Serial.println("Pret. Connectez-vous avec nRF Connect."); +} + +void loop() { +} +``` + +## 5. Tester avec une application smartphone + +Sans développer d'application dédiée, on peut tester un serveur BLE avec une application générique : + +- nRF Connect for Mobile (Nordic Semiconductor) — disponible sur Android et iOS. +- LightBlue — alternative populaire sur iOS. + +### Étapes de test + +- Téléverser le programme, ouvrir le moniteur série pour confirmer le démarrage. +- Ouvrir l'application, scanner les appareils BLE à proximité, repérer « ESP32-S3-Formation ». +- Se connecter, ouvrir le service correspondant à l'UUID défini. +- Sélectionner la caractéristique, utiliser la fonction d'écriture pour envoyer le texte « rouge », « vert », « bleu » ou « off ». + +## 6. Les notifications : envoyer des données du serveur vers le client + +À l'inverse de l'écriture (client → serveur), les notifications permettent au serveur d'envoyer spontanément une donnée au client sans attendre une requête (par exemple, la valeur d'un capteur mise à jour toutes les secondes). + +```cpp +// A ajouter a la caracteristique lors de sa creation : +// BLECharacteristic::PROPERTY_NOTIFY en plus de READ/WRITE +// et service->createCharacteristic(..., ...)->addDescriptor(new BLE2902()); + +// Puis, dans loop(), pour notifier une nouvelle temperature : +String valeur = String(bme.readTemperature()); +caracteristique->setValue(valeur.c_str()); +caracteristique->notify(); +``` + +## 7. Exercice combiné : télécommande BLE + +Réalisez une carte pilotable entièrement en BLE : écriture pour changer la couleur de la LED NeoPixel, et notification envoyant la température lue par le BME280 (Module 5) toutes les 5 secondes vers l'application smartphone. + +## Checklist de fin de module + +- [ ] Je comprends la différence entre service et caractéristique dans le modèle GATT. +- [ ] Je sais créer un serveur BLE exposant une caractéristique en lecture/écriture. +- [ ] J'ai testé la communication avec une application smartphone générique. +- [ ] Je comprends le rôle des notifications BLE. +- [ ] J'ai réalisé la télécommande BLE combinant écriture et notification. diff --git a/modules/10-energie.qmd b/modules/10-energie.qmd new file mode 100644 index 0000000..60d53fa --- /dev/null +++ b/modules/10-energie.qmd @@ -0,0 +1,114 @@ +--- +title: "Module 10 — Gestion de l'énergie" +--- + +## Objectifs du module + +- Comprendre les enjeux de consommation d'un projet ESP32-S3 alimenté sur batterie. +- Distinguer les différents modes de veille (modem-sleep, light sleep, deep sleep). +- Mettre en œuvre un réveil programmé (timer) et un réveil sur évènement externe (GPIO). +- Concevoir un capteur autonome optimisé pour l'autonomie sur batterie. + +## 1. Pourquoi se soucier de la consommation ? + +Un ESP32-S3 alimenté en continu (Wi-Fi actif, calcul permanent) consomme couramment 100 à 250 mA. Sur batterie, cela vide une pile de 2000 mAh en moins d'une journée. Pour un capteur autonome destiné à fonctionner plusieurs mois sur pile, il faut exploiter les modes de veille pour ne consommer significativement que pendant les brefs instants où la carte est réellement active. + +## 2. Les différents modes de veille + +| Mode | Consommation typique | État conservé | Réveil possible via | +|--------------|------------------------|----------------------------------------|--------------------------------| +| Actif (normal) | 80-250 mA | Tout | — | +| Modem-sleep | \~20-30 mA | RAM, CPU actif par intermittence | Automatique (Wi-Fi/BT en veille) | +| Light sleep | \~0,8 mA | RAM et état conservés | Timer, GPIO, UART... | +| Deep sleep | \~10-150 µA | RTC RAM uniquement, redémarrage du programme | Timer, GPIO (EXT0/EXT1) | + +::: {.callout-note title="Le deep sleep redémarre le programme"} +Contrairement au light sleep, sortir du deep sleep provoque un redémarrage complet du programme (comme après un reset) : `setup()` est ré-exécuté depuis le début. Seule la zone mémoire RTC (déclarée avec `RTC_DATA_ATTR`) est préservée entre deux cycles de deep sleep, ce qui permet de conserver un compteur ou un état minimal. +::: + +## 3. Deep sleep avec réveil par timer + +Cas d'usage typique : un capteur qui se réveille toutes les X minutes, effectue une mesure, l'envoie, puis se rendort. + +```cpp +#define TEMPS_REVEIL_SECONDES 60 + +RTC_DATA_ATTR int compteurReveils = 0; // conserve sa valeur entre deux deep sleep + +void setup() { + Serial.begin(115200); + delay(200); + + compteurReveils++; + Serial.printf("Reveil numero %d\n", compteurReveils); + + // ... effectuer ici la mesure, l'envoi de donnees, etc. ... + + Serial.println("Retour en deep sleep."); + esp_sleep_enable_timer_wakeup(TEMPS_REVEIL_SECONDES * 1000000ULL); // en microsecondes + esp_deep_sleep_start(); +} + +void loop() { + // Jamais atteint : le deep sleep redemarre au setup() +} +``` + +## 4. Deep sleep avec réveil sur GPIO (bouton) + +Autre cas d'usage : une carte qui reste endormie jusqu'à ce qu'un utilisateur appuie sur un bouton. + +```cpp +#define BOUTON_REVEIL GPIO_NUM_4 + +void setup() { + Serial.begin(115200); + delay(200); + + esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + if (cause == ESP_SLEEP_WAKEUP_EXT0) { + Serial.println("Reveil provoque par le bouton."); + } else { + Serial.println("Premier demarrage (pas un reveil)."); + } + + // ... traitement ... + + esp_sleep_enable_ext0_wakeup(BOUTON_REVEIL, 0); // reveil sur niveau LOW + Serial.println("Deep sleep, en attente d'un appui bouton..."); + esp_deep_sleep_start(); +} + +void loop() { +} +``` + +::: {.callout-note title="Broche compatible RTC obligatoire"} +Le réveil par GPIO (EXT0/EXT1) en deep sleep nécessite d'utiliser une broche appartenant au domaine RTC du microcontrôleur. Toutes les broches ne sont pas éligibles : vérifiez la documentation de votre référence de carte pour identifier les GPIO compatibles RTC. +::: + +## 5. Bonnes pratiques pour un projet sur batterie + +- Couper le Wi-Fi/BLE dès que la transmission de données est terminée (`WiFi.disconnect(true)`; `WiFi.mode(WIFI_OFF)`;). +- Réduire la fréquence CPU si le calcul n'est pas critique en performance (`setCpuFrequencyMhz()`). +- Limiter le temps d'éveil au strict nécessaire : mesurer, envoyer, dormir. +- Éviter les composants annexes qui consomment en continu (LED témoin, capteur non coupé) — prévoir une alimentation commutée si besoin (MOSFET de coupure). +- Pour la LED NeoPixel : elle consomme significativement plus qu'une LED simple (jusqu'à 60 mA à pleine luminosité blanche) — la couper explicitement (couleur noire) avant le deep sleep, et limiter sa luminosité (setBrightness) pour un usage sur batterie. + +## 6. Exercice : capteur météo autonome + +En combinant les modules précédents, réalisez un capteur qui : + +- Se réveille toutes les 5 minutes via un timer deep sleep. +- Lit la température et l'humidité (BME280, Module 5). +- Affiche un court flash de couleur sur la LED NeoPixel selon la température (bleu/vert/rouge, comme au Module 5), puis l'éteint. +- Retourne en deep sleep. +- Affiche dans le moniteur série, à chaque réveil, le nombre total de réveils depuis la mise sous tension (compteur en `RTC_DATA_ATTR`). + +## Checklist de fin de module + +- [ ] Je sais différencier modem-sleep, light sleep et deep sleep. +- [ ] Je sais programmer un réveil par timer en deep sleep. +- [ ] Je sais programmer un réveil par GPIO en deep sleep, sur une broche compatible RTC. +- [ ] Je connais au moins trois bonnes pratiques pour réduire la consommation d'un projet sur batterie. +- [ ] J'ai réalisé le capteur météo autonome en deep sleep. diff --git a/modules/11-mqtt.qmd b/modules/11-mqtt.qmd new file mode 100644 index 0000000..2ea95aa --- /dev/null +++ b/modules/11-mqtt.qmd @@ -0,0 +1,173 @@ +--- +title: "Module 11 — IoT & Cloud : le protocole MQTT" +--- + +## Objectifs du module + +- Comprendre le principe du protocole MQTT (publish/subscribe) et son intérêt en IoT. +- Connecter l'ESP32-S3 à un broker MQTT. +- Publier des données de capteurs et s'abonner à des commandes. +- Visualiser les données dans un tableau de bord (Node-RED ou Home Assistant). + +## 1. Pourquoi MQTT plutôt qu'HTTP pour l'IoT ? + +Le modèle HTTP vu au Module 7 fonctionne bien pour des requêtes ponctuelles, mais devient lourd pour des objets connectés qui doivent échanger fréquemment de petits messages (température toutes les secondes, changement d'état instantané). MQTT (Message Queuing Telemetry Transport) est un protocole léger conçu spécifiquement pour l'IoT, basé sur un modèle publish/subscribe (publication/abonnement) plutôt que sur des requêtes/réponses. + +## 2. Le modèle publish/subscribe + +| Élément | Rôle | +|-------------|----------------------------------------| +| Broker | Serveur central qui reçoit les messages publiés et les redistribue aux abonnés (ex : Mosquitto, HiveMQ) | +| Topic (sujet) | Chaîne hiérarchique identifiant un flux de données (ex : maison/salon/temperature) | +| Publish | Envoyer un message sur un topic donné | +| Subscribe | S'abonner à un topic pour recevoir tous les messages publiés dessus | + +Avantage clé : les appareils ne communiquent jamais directement entre eux — tout transite par le broker, ce qui simplifie grandement l'architecture (un capteur ne connaît pas l'adresse du tableau de bord qui affichera ses données, il publie simplement sur un topic). + +## 3. Choisir un broker MQTT + +- Mosquitto : broker open-source, installable localement (Raspberry Pi, PC, serveur domestique) ou utilisable en test public (test.mosquitto.org). +- HiveMQ Cloud : offre gratuite hébergée, pratique pour démarrer sans installation. +- Le broker intégré à Home Assistant : pratique si vous utilisez déjà cette plateforme domotique. + +::: {.callout-important title="Sécurité en production"} +Pour un usage de test/formation, un broker public non sécurisé (comme test.mosquitto.org) est acceptable. Pour un déploiement réel, utilisez toujours une connexion chiffrée (MQTTS, port 8883) avec authentification par identifiants ou certificat. +::: + +## 4. Connexion MQTT avec PubSubClient + +Installez la bibliothèque « PubSubClient » (Nick O'Leary) depuis le gestionnaire de bibliothèques. + +```cpp +#include +#include + +const char* ssid = "NomDuReseau"; +const char* motDePasse = "MotDePasse"; +const char* brokerMQTT = "test.mosquitto.org"; +const int portMQTT = 1883; + +WiFiClient espClient; +PubSubClient client(espClient); + +void connecterMQTT() { + while (!client.connected()) { + Serial.print("Connexion au broker MQTT..."); + String idClient = "ESP32S3-" + String(random(0xffff), HEX); + if (client.connect(idClient.c_str())) { + Serial.println(" connecte !"); + } else { + Serial.printf(" echec, code erreur: %d. Nouvelle tentative dans 2s.\n", client.state()); + delay(2000); + } + } +} + +void setup() { + Serial.begin(115200); + WiFi.begin(ssid, motDePasse); + while (WiFi.status() != WL_CONNECTED) { delay(500); } + + client.setServer(brokerMQTT, portMQTT); + connecterMQTT(); +} + +void loop() { + if (!client.connected()) connecterMQTT(); + client.loop(); // A appeler en permanence, comme handleClient() pour le serveur web +} +``` + +## 5. Publier des données de capteur + +```cpp +unsigned long dernierEnvoi = 0; +const unsigned long intervalle = 5000; + +void loop() { + if (!client.connected()) connecterMQTT(); + client.loop(); + + unsigned long maintenant = millis(); + if (maintenant - dernierEnvoi >= intervalle) { + dernierEnvoi = maintenant; + + float temperature = bme.readTemperature(); + char message[10]; + dtostrf(temperature, 4, 1, message); // conversion float -> texte + + client.publish("formation/esp32s3/temperature", message); + Serial.printf("Publie: %s\n", message); + } +} +``` + +## 6. S'abonner à un topic (recevoir des commandes) + +Réutilisons la LED NeoPixel : elle pourra être pilotée à distance en s'abonnant à un topic de commande. + +```cpp +#include +#define NEOPIXEL_PIN 48 +Adafruit_NeoPixel pixel(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); + +void callbackMQTT(char* topic, byte* payload, unsigned int longueur) { + String message; + for (unsigned int i = 0; i < longueur; i++) message += (char)payload[i]; + + Serial.printf("Message recu sur %s: %s\n", topic, message.c_str()); + + if (message == "rouge") pixel.setPixelColor(0, pixel.Color(255,0,0)); + else if (message == "vert") pixel.setPixelColor(0, pixel.Color(0,255,0)); + else if (message == "bleu") pixel.setPixelColor(0, pixel.Color(0,0,255)); + else if (message == "off") pixel.setPixelColor(0, pixel.Color(0,0,0)); + pixel.show(); +} + +void connecterMQTT() { + while (!client.connected()) { + String idClient = "ESP32S3-" + String(random(0xffff), HEX); + if (client.connect(idClient.c_str())) { + client.subscribe("formation/esp32s3/commande"); + } else { + delay(2000); + } + } +} + +void setup() { + pixel.begin(); + // ... connexion WiFi ... + client.setServer(brokerMQTT, portMQTT); + client.setCallback(callbackMQTT); + connecterMQTT(); +} +``` + +## 7. Visualiser les données : Node-RED ou Home Assistant + +Une fois les données publiées sur le broker, il est possible de les visualiser sans écrire de code supplémentaire : + +- Node-RED : outil de programmation visuelle par flux, avec un nœud MQTT natif et un tableau de bord (dashboard) configurable en quelques clics. +- Home Assistant : plateforme domotique qui peut découvrir automatiquement les topics MQTT et générer des cartes de suivi (courbes de température, boutons de commande). + +::: {.callout-note title="Portée pédagogique"} +La mise en place détaillée de Node-RED ou Home Assistant dépasse le cadre strict de la programmation Arduino/ESP32 ; ce module se concentre sur la partie « objet connecté » (ESP32-S3). L'installation et la configuration de l'outil de visualisation pourront faire l'objet d'un support complémentaire selon les besoins du groupe. +::: + +## 8. Exercice final du module : station météo connectée + +En combinant tous les modules précédents, réalisez une station météo IoT complète : + +- Lecture température/humidité via le BME280 (Module 5). +- Publication MQTT toutes les 30 secondes sur un topic dédié. +- Abonnement à un topic de commande pilotant la couleur de la LED NeoPixel. +- Affichage local sur l'écran OLED de la dernière valeur publiée et de l'état de connexion MQTT. + +## Checklist de fin de module + +- [ ] Je comprends le modèle publish/subscribe et le rôle du broker. +- [ ] Je sais connecter l'ESP32-S3 à un broker MQTT. +- [ ] Je sais publier une donnée de capteur sur un topic. +- [ ] Je sais m'abonner à un topic et réagir à un message reçu. +- [ ] J'ai réalisé la station météo connectée combinant capteur, MQTT, OLED et LED NeoPixel. diff --git a/modules/12-projetfinal.qmd b/modules/12-projetfinal.qmd new file mode 100644 index 0000000..eaaeec9 --- /dev/null +++ b/modules/12-projetfinal.qmd @@ -0,0 +1,85 @@ +--- +title: "Module 12 — Projet final" +--- + +## Objectifs du module + +- Mobiliser l'ensemble des compétences acquises (GPIO, PWM, ADC, I2C, interruptions, Wi-Fi, BLE, énergie, MQTT) dans un projet personnel cohérent. +- Rédiger un cahier des charges simple avant de coder. +- Structurer un programme Arduino de taille conséquente (plusieurs fichiers, fonctions bien séparées). +- Présenter et démontrer son projet. + +## 1. Méthodologie : avant de coder + +Un projet réussi commence par une phase de cadrage, même brève. Avant d'ouvrir l'IDE, répondez par écrit aux questions suivantes : + +- Quel problème mon projet résout-il, ou quel besoin satisfait-il ? +- Quelles sont les fonctionnalités indispensables (MVP - produit minimum viable) et lesquelles sont « bonus » si le temps le permet ? +- Quel matériel est nécessaire (capteurs, actionneurs, alimentation) et est-il disponible ? +- Le projet doit-il fonctionner de façon autonome (batterie) ou reste-t-il branché en continu ? +- Quels modules de la formation seront mobilisés ? + +## 2. Exemples de projets (par ordre de complexité croissante) + +| Projet | Modules mobilisés | Description | +|------------------------------|---------------------|----------------------------------------| +| Station météo de bureau | 1, 2, 3, 5 | Écran OLED affichant température/humidité locales, LED NeoPixel comme indicateur de confort | +| Station météo connectée | 5, 7 ou 11 | La précédente, mais publiant les données sur Internet (API ou MQTT) et consultable à distance | +| Capteur autonome sur batterie | 5, 10, 11 | Mesure périodique avec deep sleep, transmission MQTT, autonomie de plusieurs semaines | +| Domotique locale | 2, 3, 8 | Serveur web pilotant plusieurs relais/LED, avec retour d'état en temps réel | +| Télécommande BLE personnalisée | 6, 9 | Boîtier avec boutons/encodeur pilotant un appareil via BLE (ex : diaporama, musique) | +| Jeu de réflexes lumineux | 2, 4, 6 | Jeu type « Simon » utilisant plusieurs LED (ou la NeoPixel en RGB) et un buzzer, avec score affiché en série | + +::: {.callout-note title="Un projet libre est aussi possible"} +Cette liste est indicative : n'importe quel projet personnel combinant au moins trois modules de la formation et incluant une utilisation réfléchie de la LED NeoPixel est recevable. +::: + +## 3. Cahier des charges type (à compléter) + +| Rubrique | À compléter | +|----------------------------------------|---------------| +| Nom du projet | | +| Objectif en une phrase | | +| Fonctionnalités indispensables | | +| Fonctionnalités bonus (si le temps le permet) | | +| Matériel nécessaire | | +| Modules de la formation mobilisés | | +| Contraintes (autonomie, taille, coût...) | | + +## 4. Structurer un projet de taille conséquente + +Au-delà d'une centaine de lignes, un seul fichier .ino devient difficile à maintenir. L'IDE Arduino permet de scinder un croquis en plusieurs onglets/fichiers, automatiquement inclus à la compilation : + +- MonProjet.ino : contient uniquement `setup()` et `loop()`, orchestrant les appels aux autres fonctions. +- capteurs.h / capteurs.cpp (ou simplement un onglet capteurs.ino) : fonctions de lecture et traitement des capteurs. +- affichage.ino : fonctions liées à l'écran OLED et à la LED NeoPixel. +- reseau.ino : fonctions Wi-Fi/MQTT/BLE. + +::: {.callout-tip title="Bonne pratique de structuration"} +Une fonction doit avoir une seule responsabilité claire (ex : `lireTemperature()`, `afficherEcran()`, `publierMQTT()`). Cette organisation facilite grandement le débogage et la relecture, surtout en formation collective où le code peut être partagé et commenté entre apprenants. +::: + +## 5. Grille d'auto-évaluation avant présentation + +| Critère | Validé ? | +|----------------------------------------|------------| +| Le projet répond au besoin défini dans le cahier des charges | ☐ | +| Le code compile sans erreur ni avertissement bloquant | ☐ | +| Les fonctions sont nommées clairement et bien séparées | ☐ | +| Le programme gère les cas d'erreur (capteur non détecté, Wi-Fi indisponible...) | ☐ | +| La LED NeoPixel est utilisée de façon pertinente (état, alerte, feedback) | ☐ | +| Le projet a été testé sur une durée représentative de son usage réel | ☐ | +| Une courte documentation (schéma de câblage, liste du matériel) accompagne le code | ☐ | + +## 6. Présentation du projet + +Chaque participant présente son projet en quelques minutes : + +- Démonstration du fonctionnement réel sur la carte. +- Explication des choix techniques (pourquoi ce protocole, cette architecture). +- Difficultés rencontrées et solutions apportées. +- Pistes d'amélioration si le projet devait être poursuivi. + +## Conclusion de la formation + +Ce parcours a couvert la prise en main du matériel, les entrées/sorties, les signaux analogiques, les bus de communication, la gestion du temps et des évènements, la connectivité Wi-Fi et BLE, la gestion de l'énergie et l'IoT via MQTT — un socle de compétences complet pour aborder de façon autonome tout projet basé sur l'ESP32-S3 avec le framework Arduino. La suite naturelle consiste à approfondir un domaine particulier selon vos projets futurs : traitement du signal, IA embarquée (TinyML), protocoles radio longue portée (LoRa), ou intégration à des écosystèmes domotiques existants. diff --git a/modules/synthese-materiel.qmd b/modules/synthese-materiel.qmd new file mode 100644 index 0000000..6dbd5a3 --- /dev/null +++ b/modules/synthese-materiel.qmd @@ -0,0 +1,81 @@ +--- +title: "Synthèse de la formation & liste de matériel" +--- + +## 1. Vue d'ensemble des modules + +| Module | Titre | Compétences clés | +|----------|-----------------------------|----------------------------------------| +| 0 | Prérequis & Installation | Arduino IDE, pilotes USB, ajout du support ESP32, premier Blink | +| 1 | Découverte du microcontrôleur | Architecture ESP32-S3, différences vs Arduino Uno, lecture du pinout | +| 2 | GPIO & LED NeoPixel | Entrées/sorties numériques, anti-rebond, pilotage de la LED RGB intégrée | +| 3 | PWM & ADC | Variateur de luminosité, lecture analogique, potentiomètre | +| 4 | Communication série & debug | UART, ports série multiples, console de commandes | +| 5 | Bus I2C et SPI | Scanner I2C, écran OLED, capteur BME280, comparatif I2C/SPI | +| 6 | Interruptions & Timers | `millis()`, `attachInterrupt()`, encodeur rotatif, timers matériels | +| 7 | Wi-Fi | Mode station/point d'accès, requêtes HTTP, API météo | +| 8 | Serveur Web embarqué | WebServer.h, page HTML de contrôle, notion de WebSocket | +| 9 | Bluetooth Low Energy | Serveur BLE, services/caractéristiques, notifications | +| 10 | Gestion de l'énergie | Modes de veille, deep sleep, réveil timer/GPIO, capteur autonome | +| 11 | IoT & MQTT | Broker MQTT, publish/subscribe, station météo connectée | +| 12 | Projet final | Cahier des charges, structuration de projet, présentation | + +## 2. Liste de matériel consolidée (à acheter) + +Cette liste regroupe l'ensemble des composants nécessaires pour réaliser tous les exercices de la formation. Les quantités indiquées correspondent à un poste de travail (un apprenant ou un binôme). + +### 2.1 Carte et informatique + +| Article | Quantité | Modules concernés | Remarques | +|----------------------------------------|------------|---------------------|----------------------------------------| +| Carte ESP32-S3-DevKitC-1 (WROOM-1) | 1 | Tous | Vérifier la présence d'une LED NeoPixel intégrée et la référence exacte du pinout | +| Câble USB-C (données, pas uniquement charge) | 1 | Tous | Indispensable pour la programmation et l'alimentation | +| Ordinateur avec Arduino IDE installé | 1 | Tous | Voir Module 0 pour l'installation | + +### 2.2 Composants électroniques de base + +| Article | Quantité | Modules concernés | Remarques | +|----------------------------------------|------------|------------------------------|-------------------------------------| +| Breadboard (plaque d'essai) 830 points | 1 | 2, 3, 4, 5, 6 | Support de câblage sans soudure | +| Kit de fils de câblage (jumpers M-M, M-F) | 1 kit | Tous les TP câblés | Prévoir mâle-mâle et mâle-femelle | +| LED 5 mm (couleurs variées) | 4 à 6 | Module 2 (chenillard) | Rouge, vert, bleu, jaune conseillées | +| Résistances 220 Ω | 6 | Module 2 | Protection des LED | +| Résistances 10 kΩ | 2 | Complément pull-down si besoin | Facultatif selon montage | +| Bouton-poussoir (push-button) 4 pattes | 2 | Modules 2, 4, 6 | Un de rechange conseillé | +| Potentiomètre rotatif 10 kΩ | 1 | Module 3 | Avec bouton de préhension si possible | + +### 2.3 Modules et capteurs + +| Article | Quantité | Modules concernés | Remarques | +|----------------------------------------|------------|---------------------|----------------------------------------| +| Écran OLED I2C SSD1306 0,96" (128x64) | 1 | 5, 7, 8, 11 | Vérifier alimentation 3,3V compatible | +| Capteur BME280 (température/humidité/pression), I2C | 1 | 5, 10, 11 | Attention aux clones BMP280 (pas d'humidité) : bien vérifier la référence BME280 | +| Encodeur rotatif avec bouton intégré (type KY-040) | 1 | 6 | Génère 2 signaux CLK/DT + bouton poussoir | + +### 2.4 Alimentation et énergie (Module 10 et projets autonomes) + +| Article | Quantité | Modules concernés | Remarques | +|----------------------------------------|------------|-----------------------|----------------------------------------| +| Pile ou batterie externe (powerbank, ou support piles AA/LiPo) | 1 | Module 10, projet final | Selon le projet choisi ; un support 2xAA avec câble JST suffit pour les tests | +| Câble/connecteur adapté à l'alimentation choisie | 1 | Module 10 | Vérifier compatibilité avec l'entrée d'alimentation de la carte | + +### 2.5 Facultatif / selon projet final + +Selon le projet choisi par chaque apprenant au Module 12, du matériel additionnel peut être nécessaire : relais, buzzer, servomoteur, capteur supplémentaire (PIR, ultrason...), boîtier d'impression 3D, etc. Ce matériel n'est pas listé ici car dépendant du projet individuel — à définir une fois le cahier des charges rédigé (voir Module 12, section 3). + +::: {.callout-note title="Application smartphone (gratuite, pas d'achat)"} +Pour le Module 9 (BLE), chaque apprenant doit disposer d'un smartphone avec l'application gratuite « nRF Connect for Mobile » (Android/iOS) ou équivalent (LightBlue sur iOS). Aucun matériel supplémentaire à acheter pour ce module. +::: + +## 3. Tableau récapitulatif quantités globales + +| Catégorie | Nombre de références distinctes | +|--------------------------------|-----------------------------------| +| Carte et informatique | 3 | +| Composants électroniques de base | 7 | +| Modules et capteurs | 3 | +| Alimentation / énergie | 2 | + +::: {.callout-tip title="Astuce achat groupé"} +La plupart de ces composants (hors carte ESP32-S3 et écran OLED/BME280) sont généralement disponibles dans un kit de démarrage Arduino/ESP32 générique, ce qui peut s'avérer plus économique que des achats à l'unité pour un groupe de plusieurs apprenants. +:::