hors suivi
Leçon

Un microcontrôleur n'est pas un ordinateur

Jour 1 · Descendre dans l'objet · 20 min

Au module M1, vous avez fait tourner un broker et des scripts Python sur votre poste. Vous descendez maintenant dans l'objet lui-même — et les règles y sont différentes.

Votre posteESP32
Mémoire vive16 Go520 Ko
Stockage500 Go4 Mo de flash
Processeurquelques GHz240 MHz, deux cœurs
SystèmemacOS, Linux, WindowsFreeRTOS, ou rien du tout
Alimentationsecteurpile ou batterie
Si le programme planteon le relancel'objet est mort sur son poteau
La contrainte qui change tout

Un capteur installé sur un toit ou dans une gaine technique n'est pas redémarrable. Le firmware doit tenir des mois sans intervention : pas de fuite mémoire, pas de blocage, et un chien de garde qui redémarre si tout se fige.

Ce qui remplace le système d'exploitation

L'ESP32 fait tourner FreeRTOS, un ordonnanceur temps réel minimal. Il ne gère ni fichiers ni utilisateurs : il découpe le temps entre des tâches, chacune avec sa priorité et sa propre pile mémoire.

C'est ce qui permet de lire un capteur toutes les secondes pendant qu'une autre tâche maintient la connexion Wi-Fi, sans que l'une bloque l'autre.

Deux cœurs, deux rôles

L'ESP32 en a deux. Par convention, le cœur 0 porte la pile réseau — Wi-Fi et Bluetooth —, le cœur 1 votre application. Cette séparation évite qu'un traitement un peu long fasse tomber la connexion.

Le fil du module

Vous allez reprendre le capteur Thermeo de M1 et le rendre autonome : capable de mesurer, de filtrer le bruit, de décider seul si la valeur mérite d'être transmise, et de dormir entre deux mesures assez profondément pour tenir cinq ans sur pile.

✓ terminé
Leçon

Lire une grandeur physique

Jour 1 · Descendre dans l'objet · 25 min

Un capteur de température ne renvoie pas « 21,4 ». Il renvoie une tension, que le convertisseur analogique-numérique traduit en nombre entier. Tout le reste est votre travail.

Le convertisseur

L'ADC de l'ESP32 est un 12 bits : il rend une valeur entre 0 et 4095 pour une tension entre 0 et 3,3 V. La conversion est donc directe :

float tension = lecture * 3.3 / 4095.0;
Trois pièges de l'ADC

Il n'est pas linéaire aux extrémités : évitez les valeurs sous 0,15 V et au-dessus de 3,1 V.
Il est bruité : deux lectures consécutives sur une entrée stable diffèrent de quelques unités. C'est le sujet du jour 2.
Les broches de l'ADC2 sont indisponibles quand le Wi-Fi tourne sur ESP32. Utilisez l'ADC1 — les GPIO 32 à 39.

Capteurs numériques

Beaucoup de capteurs font la conversion eux-mêmes et exposent une valeur via un bus. C'est le cas du DHT22 que vous utiliserez, et plus généralement des capteurs I²C. On y gagne en précision et en simplicité — au prix d'une dépendance à une bibliothèque.

BusUsageRemarque
AnalogiqueCapteurs simples, potentiomètresConversion et bruit à votre charge
I²CLa majorité des capteurs environnementauxDeux fils, plusieurs capteurs
SPICapteurs rapides, écrans, mémoiresPlus rapide, plus de fils
1-WireDS18B20, DHT22Un seul fil de données

Et le STM32 ?

Le programme du parcours mentionne le STM32 — HAL, interruptions, DMA. Nous le traiterons en comparaison, pas en pratique.

Pourquoi cette limite est assumée

L'émulation QEMU d'un STM32 n'implémente pas fidèlement les périphériques analogiques : un TP d'acquisition ADC y donnerait des résultats qui n'ont rien à voir avec le matériel. Mieux vaut maîtriser une plateforme réellement simulable que se donner l'illusion d'en connaître deux.

Les concepts — interruptions, DMA, horloges — sont transposables ; c'est ce que nous travaillerons. Si des cartes sont approvisionnées, ce point sera repris.

✓ terminé
Quiz

Quiz — Microcontrôleur et acquisition

Jour 1 · Descendre dans l'objet · 8 min

1. Pourquoi le cœur 0 de l'ESP32 est-il réservé à la pile réseau ?

2. Une lecture ADC vaut 2048 sur un ESP32. Quelle tension approximative ?

3. Votre montage utilise le Wi-Fi et lit un capteur analogique. Quelle broche éviter ?

4. Pourquoi ne traitons-nous pas le STM32 en TP ?

✓ terminé
Travaux pratiques

TP 1 — Deux tâches qui cohabitent

Jour 1 · Descendre dans l'objet · 1 h

Structurer un firmware en tâches FreeRTOS plutôt qu'en une boucle unique.

Environnement

Wokwi, projet ESP32, capteur DHT22 sur la GPIO 15 — le même montage qu'au TP 2 du jour 3 de M1. Vous pouvez repartir de ce projet.

  1. Créez un projet ESP32 sur Wokwi avec un DHT22 sur la GPIO 15 et une LED sur la GPIO 2.
  2. Écrivez un firmware à deux tâches : l'une lit le capteur toutes les deux secondes, l'autre fait clignoter la LED toutes les 200 ms. Notez qu'aucune ne bloque l'autre :
    #include "DHTesp.h"
    
    DHTesp dht;
    volatile float derniere = 0;
    
    void tacheCapteur(void *p) {
      for (;;) {
        derniere = dht.getTempAndHumidity().temperature;
        Serial.printf("mesure %.1f\n", derniere);
        vTaskDelay(pdMS_TO_TICKS(2000));
      }
    }
    
    void tacheLed(void *p) {
      pinMode(2, OUTPUT);
      for (;;) {
        digitalWrite(2, !digitalRead(2));
        vTaskDelay(pdMS_TO_TICKS(200));
      }
    }
    
    void setup() {
      Serial.begin(115200);
      dht.setup(15, DHTesp::DHT22);
      xTaskCreatePinnedToCore(tacheCapteur, "capteur", 4096, NULL, 1, NULL, 1);
      xTaskCreatePinnedToCore(tacheLed, "led", 2048, NULL, 1, NULL, 1);
    }
    
    void loop() { vTaskDelay(pdMS_TO_TICKS(1000)); }
  3. Lancez la simulation : la LED clignote régulièrement pendant que les mesures s'affichent. Les deux tâches progressent en parallèle.
  4. Faites l'expérience inverse pour comprendre l'intérêt : remplacez vTaskDelay par delay dans la tâche capteur, et mettez tout dans loop() :
    void loop() {
      float t = dht.getTempAndHumidity().temperature;
      Serial.printf("mesure %.1f\n", t);
      delay(2000);                    // bloque tout pendant 2 s
      digitalWrite(2, !digitalRead(2));
    }
  5. Observez : la LED ne clignote plus qu'une fois toutes les deux secondes. C'est exactement le problème que FreeRTOS résout.
  6. Revenez à la version à deux tâches. Réduisez la pile de la tâche capteur à 512 octets et relancez : le firmware plante. Lisez le message — c'est un débordement de pile, la panne la plus courante en embarqué.
Questions de réflexion — à préparer par écrit
  • Quelle différence exacte entre delay() et vTaskDelay() ?
  • Pourquoi derniere est-elle déclarée volatile ?
  • Comment dimensionner la pile d'une tâche sans procéder par essais et erreurs ?
✓ terminé
Travaux pratiques

TP 2 — Échantillonner régulièrement

Jour 1 · Descendre dans l'objet · 1 h

Acquérir à cadence fixe par interruption de timer, et non par attente active.

  1. Un traitement de signal exige un échantillonnage régulier. Une boucle avec delay dérive : le temps de traitement s'ajoute à l'attente.
  2. Mettez en place un timer matériel qui déclenche une interruption à 10 Hz. Notez IRAM_ATTR : la routine doit résider en RAM interne :
    hw_timer_t *timer = NULL;
    volatile bool tick = false;
    
    void IRAM_ATTR surTimer() { tick = true; }
    
    void setup() {
      Serial.begin(115200);
      timer = timerBegin(0, 80, true);          // 80 MHz / 80 = 1 MHz
      timerAttachInterrupt(timer, &surTimer, true);
      timerAlarmWrite(timer, 100000, true);     // 100 000 µs = 100 ms
      timerAlarmEnable(timer);
    }
    
    void loop() {
      if (tick) {
        tick = false;
        int brut = analogRead(34);
        Serial.println(brut);
      }
    }
  3. Ajoutez un potentiomètre sur la GPIO 34 dans le schéma Wokwi et faites-le varier : les valeurs suivent.
  4. Vérifiez la régularité : affichez micros() à chaque tick et calculez l'écart entre deux mesures successives sur cinquante échantillons. Il doit rester très proche de 100 000 µs.
  5. Comparez avec une boucle à delay(100) qui contient un traitement de 30 ms. Mesurez la période réelle :
    void loop() {
      unsigned long t0 = micros();
      analogRead(34);
      delay(30);            // simule un traitement
      delay(100);
      Serial.println(micros() - t0);
    }
  6. L'écart est visible : 130 ms au lieu de 100. Consignez les deux mesures, c'est le livrable de ce TP.
Questions de réflexion — à préparer par écrit
  • Pourquoi une routine d'interruption ne doit-elle contenir ni Serial.print ni allocation mémoire ?
  • À quoi sert le drapeau tick plutôt que de lire le capteur directement dans l'interruption ?
  • Quelle fréquence d'échantillonnage retenir pour un signal dont on veut observer des variations à 2 Hz ?
✓ terminé
Point de contrôle

Point de contrôle — fin du jour 1

Jour 1 · Descendre dans l'objet · 15 min

Vérifiez avant de continuer
Deux tâches FreeRTOS tournent en parallèle sans se bloquer
J'ai constaté le blocage provoqué par delay() et je sais l'expliquer
J'ai provoqué un débordement de pile et su le diagnostiquer
Un timer matériel déclenche une acquisition à cadence fixe
J'ai mesuré la dérive d'une boucle à delay et je l'ai chiffrée
Je sais pourquoi l'ADC2 est inutilisable quand le Wi-Fi tourne
Ce que l'encadrant vérifiera

Il vous demandera de montrer la dérive : les deux séries de mesures, et l'écart chiffré entre la période visée et la période réelle. Un ordre de grandeur ne suffira pas.

✓ terminé
Leçon

Pourquoi traiter dans l'objet

Jour 2 · Traiter à la source · 20 min

Le réflexe naturel est d'envoyer tout au cloud et de laisser le serveur trier. Sur un capteur sur pile, c'est la garantie de l'échec.

Sans traitement local capteur 1 mesure/s 86 400/j réseau saturé cloud filtre et décide pile vidée en jours Avec traitement local capteur 1 mesure/s filtre + seuil dans l'objet ~100/j cloud pile tenue des années
Le même capteur, selon qu'il émet tout ou seulement ce qui compte.

Quatre raisons de traiter à la source

RaisonCe que cela évite
ÉnergieChaque émission radio coûte cent fois plus qu'un calcul local. Émettre 100 fois par jour au lieu de 86 400 change l'autonomie d'un facteur mille.
Bande passanteCent capteurs à 1 Hz saturent un réseau LPWAN, dont le quota se compte en dizaines de messages par jour.
LatenceUne détection de seuil qui doit déclencher une action locale ne peut pas attendre un aller-retour cloud.
ConfidentialitéCe qui n'est jamais transmis ne peut pas fuiter. Un capteur de présence peut n'émettre qu'un compteur, jamais le signal brut.
La question à se poser à chaque mesure

Cette valeur apprend-elle quelque chose ? Une température identique à la précédente à 0,1 °C près n'apprend rien. Un écart de 3 °C en dix secondes, si.

C'est le principe de l'émission sur événement plutôt que périodique, que vous mettrez en œuvre au TP 4.

Ce qui reste au cloud

Le traitement local ne remplace pas le serveur : il le décharge. L'historisation longue, les corrélations entre capteurs, les tableaux de bord et les modèles restent côté cloud. L'objet décide seulement quoi émettre, et quand.

Le revers

Ce qui n'est pas transmis est perdu à jamais. Si votre seuil est mal réglé, vous ne pourrez pas réanalyser après coup : la donnée brute n'a jamais quitté l'objet. D'où la pratique courante d'un battement de cœur — une valeur transmise périodiquement même sans événement, pour garder une trace et prouver que le capteur vit.

✓ terminé
Leçon

Filtrer un signal bruité

Jour 2 · Traiter à la source · 25 min

Deux lectures ADC successives sur une entrée parfaitement stable ne donnent pas la même valeur. Ce bruit vient du convertisseur, de l'alimentation, du capteur lui-même. Le filtrer est la première opération de tout traitement embarqué.

Trois filtres, du plus simple au plus fin

La moyenne glissante

On garde les N dernières mesures et on en fait la moyenne. Simple, efficace, mais il faut stocker N valeurs et la réponse est lente.

#define N 10
float buf[N]; int idx = 0;

float moyenne(float v) {
  buf[idx] = v; idx = (idx + 1) % N;
  float s = 0;
  for (int i = 0; i < N; i++) s += buf[i];
  return s / N;
}

Le filtre exponentiel

Une seule variable en mémoire, une seule multiplication. C'est le filtre du pauvre, et c'est presque toujours le bon choix en embarqué.

float y = 0;
const float alpha = 0.2;   // entre 0 et 1

float lisser(float v) {
  y = alpha * v + (1 - alpha) * y;
  return y;
}
Comment régler alpha

Proche de 1, le filtre suit vite mais laisse passer le bruit. Proche de 0, il lisse fort mais réagit lentement. 0,1 à 0,3 convient à une grandeur physique lente comme une température. Vous le vérifierez expérimentalement au TP.

La médiane

On trie les N dernières valeurs et on prend celle du milieu. C'est le seul qui élimine complètement une valeur aberrante isolée — un pic parasite — là où une moyenne se laisse contaminer.

FiltreMémoireCalculBon pour
Moyenne glissanteN valeursN additionsBruit régulier
Exponentiel1 valeur2 opérationsLe cas général
MédianeN valeursun triPics parasites isolés
Ne filtrez pas ce que vous devez détecter

Un filtre lisse les variations rapides. Si vous cherchez précisément à détecter une variation brutale, un filtre trop agressif l'effacera. Filtrer et détecter demandent des réglages opposés — c'est le piège du TP 4.

✓ terminé
Quiz

Quiz — Edge computing et filtrage

Jour 2 · Traiter à la source · 8 min

1. Pourquoi émettre coûte-t-il tellement plus que calculer ?

2. Quel filtre élimine un pic parasite isolé sans se laisser contaminer ?

3. Vous mettez alpha à 0,9 dans un filtre exponentiel. Que se passe-t-il ?

4. Pourquoi conserver un battement de cœur périodique malgré l'émission sur événement ?

✓ terminé
Travaux pratiques

TP 3 — Dompter le bruit

Jour 2 · Traiter à la source · 1 h 15

Implémenter et comparer trois filtres sur un signal réellement bruité.

  1. Reprenez le montage du TP 2 avec le potentiomètre sur la GPIO 34.
  2. Implémentez les trois filtres et affichez les quatre valeurs côte à côte, pour les tracer ensuite :
    float expo = 0;
    const float ALPHA = 0.2;
    #define N 9
    float buf[N]; int idx = 0; bool plein = false;
    
    float mediane() {
      float c[N];
      memcpy(c, buf, sizeof(buf));
      for (int i = 1; i < N; i++)          // tri par insertion, N est petit
        for (int j = i; j > 0 && c[j-1] > c[j]; j--) {
          float t = c[j]; c[j] = c[j-1]; c[j-1] = t;
        }
      return c[N/2];
    }
    
    void loop() {
      if (!tick) return;
      tick = false;
      float brut = analogRead(34);
      buf[idx] = brut; idx = (idx + 1) % N; if (idx == 0) plein = true;
      expo = ALPHA * brut + (1 - ALPHA) * expo;
      float moy = 0;
      for (int i = 0; i < N; i++) moy += buf[i];
      moy /= N;
      Serial.printf("%.0f,%.1f,%.1f,%.1f\n", brut, moy, expo, mediane());
    }
  3. Laissez le potentiomètre immobile trente secondes et copiez la sortie du moniteur série. Collez-la dans un tableur et tracez les quatre courbes.
  4. Mesurez l'écart-type de chaque série sur cette période stable. Vous devez constater une réduction nette du bruit, chiffrée.
  5. Faites maintenant varier brusquement le potentiomètre et observez : chaque filtre met un temps différent à rattraper la nouvelle valeur. Mesurez ce temps de réponse.
  6. Refaites l'expérience avec alpha à 0,05 puis à 0,8. Consignez les trois couples (bruit résiduel, temps de réponse) : c'est le compromis fondamental du filtrage.
  7. Simulez un pic parasite en touchant brièvement l'entrée. Vérifiez que seule la médiane l'ignore complètement.
Questions de réflexion — à préparer par écrit
  • Quel filtre retenez-vous pour Thermeo, et pourquoi ?
  • Le tri de la médiane coûte N² comparaisons. À partir de quel N cela devient-il gênant à 10 Hz ?
  • Pourquoi l'écart-type est-il une meilleure mesure du bruit que l'écart maximal observé ?
✓ terminé
Leçon

Décider dans l'objet

Jour 2 · Traiter à la source · 20 min

Filtrer ne suffit pas : il faut décider quoi émettre. C'est là que le capteur devient intelligent — et que l'autonomie se gagne.

Trois stratégies

StratégieRègleMessages par jour
PériodiqueJ'émets toutes les N secondes86 400 à 1 Hz — inacceptable
Sur seuilJ'émets si la valeur dépasse une borneVariable, potentiellement zéro… ou un déluge si le signal oscille autour du seuil
Sur variationJ'émets si l'écart avec la dernière valeur émise dépasse δProportionnel à l'activité réelle — c'est généralement le bon choix
Le piège du seuil qui oscille

Un signal qui fluctue autour de la borne déclenche à chaque passage : 21,0 / 21,1 / 20,9 / 21,1 sur un seuil à 21 produit une rafale d'alertes.

La parade est l'hystérésis : on déclenche à 21,5 et on ne réarme qu'en dessous de 20,5. Deux bornes au lieu d'une, et le bavardage disparaît.

Le motif complet

Un capteur bien conçu combine trois règles :

  1. Émission sur variation — dès que l'écart dépasse δ.
  2. Battement de cœur — au moins une valeur toutes les quinze minutes, même sans variation, pour prouver qu'il vit.
  3. Plafond d'émission — jamais plus d'un message par minute, pour se protéger d'un capteur défaillant qui bavarderait sans fin.
Le plafond n'est pas une précaution théorique

Un capteur dont l'entrée se déconnecte produit du bruit pur : sans plafond, il émet en continu, vide sa pile en quelques heures et sature le broker. La règle du plafond est ce qui distingue une maquette d'un produit.

✓ terminé
Travaux pratiques

TP 4 — Un capteur qui décide

Jour 2 · Traiter à la source · 1 h 15

Mettre en œuvre l'émission sur variation, l'hystérésis et le plafond.

  1. Repartez du TP 3 en gardant le filtre exponentiel — c'est celui que vous conserverez.
  2. Implémentez les trois règles :
    const float DELTA = 0.5;              // variation qui justifie une émission
    const unsigned long COEUR = 900000;   // battement : 15 min
    const unsigned long PLAFOND = 60000;  // au plus un message par minute
    
    float derniereEmise = -999;
    unsigned long tEmission = 0;
    
    bool doitEmettre(float v, unsigned long maintenant) {
      if (maintenant - tEmission < PLAFOND) return false;       // plafond
      if (fabs(v - derniereEmise) >= DELTA) return true;        // variation
      if (maintenant - tEmission >= COEUR) return true;         // battement
      return false;
    }
  3. Ajoutez un compteur de messages émis et de mesures effectuées, affiché toutes les trente secondes. Le rapport entre les deux est votre gain.
  4. Laissez tourner deux minutes en faisant varier lentement le potentiomètre. Relevez le rapport mesures / émissions.
  5. Ajoutez maintenant une alarme de seuil avec hystérésis :
    const float HAUT = 24.0, BAS = 23.0;
    bool enAlarme = false;
    
    void verifierAlarme(float v) {
      if (!enAlarme && v > HAUT)      { enAlarme = true;  Serial.println("ALARME"); }
      else if (enAlarme && v < BAS)   { enAlarme = false; Serial.println("fin alarme"); }
    }
  6. Faites osciller la valeur autour de 24 et vérifiez qu'une seule alarme est déclenchée, pas une rafale.
  7. Retirez l'hystérésis — un seul seuil à 24 — et refaites la même manipulation. Comptez les déclenchements :
    if (v > 24.0) Serial.println("ALARME");   // sans hystérésis
  8. Consignez les deux comptages. C'est la démonstration la plus parlante du module.
Questions de réflexion — à préparer par écrit
  • Quelles valeurs de δ, de battement et de plafond retiendriez-vous pour Thermeo ?
  • Que se passe-t-il si δ est plus petit que le bruit résiduel du filtre ?
  • Un capteur qui n'émet rien pendant une heure : comment distinguer « rien à signaler » de « en panne » ?
✓ terminé
Point de contrôle

Point de contrôle — fin du jour 2

Jour 2 · Traiter à la source · 15 min

Vérifiez avant de continuer
Mes trois filtres tournent et j'ai tracé les quatre courbes
J'ai chiffré la réduction de bruit par l'écart-type, pas à l'œil
J'ai mesuré le temps de réponse de chaque filtre
J'ai constaté que seule la médiane ignore un pic isolé
Mon capteur n'émet que sur variation, avec battement de cœur et plafond
J'ai comparé le nombre de déclenchements avec et sans hystérésis
Je sais expliquer pourquoi filtrer et détecter demandent des réglages opposés
✓ terminé
Leçon

Faire durer une pile cinq ans

Jour 3 · Énergie, sécurité et assemblage · 25 min

Thermeo vise cinq ans d'autonomie. Ce n'est pas une question de composants, mais d'arithmétique — et le calcul est à la portée de tous.

160 mA 10 µA réveil sommeil profond — 15 min sommeil profond — 15 min 3 s
L'autonomie ne se joue pas sur la consommation en veille, mais sur la durée des réveils.

Les modes de l'ESP32

ModeConsommationCe qui reste actif
Actif, Wi-Fi émettant~160 mATout
Actif, radio éteinte~40 mAProcesseur
Light sleep~0,8 mARAM conservée, réveil rapide
Deep sleep~10 µAUn minuteur, et la mémoire RTC
Le facteur qui décide

Entre le mode actif et le sommeil profond, il y a un rapport de 16 000. L'autonomie ne se joue donc pas sur ce que consomme l'objet endormi, mais sur la fraction de temps qu'il passe éveillé.

Le calcul

Prenons un capteur qui se réveille toutes les quinze minutes, reste éveillé trois secondes pour mesurer et émettre, sur une pile de 3 000 mAh.

Réveils par jour   : 24 x 4                      = 96
Temps éveillé      : 96 x 3 s                    = 288 s = 0,08 h
Charge éveillé     : 0,08 h x 160 mA             = 12,8 mAh/j
Charge endormi     : 23,92 h x 0,01 mA           = 0,24 mAh/j
                                                 ─────────────
Total quotidien                                  = 13,04 mAh/j

Autonomie          : 3000 / 13,04                = 230 jours

Sept mois. Loin des cinq ans visés. Le poste dominant saute aux yeux : les trois secondes de réveil pèsent cinquante fois plus que les vingt-quatre heures de sommeil.

Où agir

  1. Raccourcir le réveil. Trois secondes, c'est surtout l'association Wi-Fi. La mémoriser en RAM RTC fait tomber à moins d'une seconde.
  2. Espacer les réveils. Passer à une heure divise la consommation par quatre.
  3. Grouper les émissions. Mesurer toutes les quinze minutes en gardant les valeurs en RAM RTC, et n'émettre qu'une fois par heure.
L'exercice du TP

Vous refaites ce calcul avec les trois optimisations et vous cherchez la combinaison qui atteint cinq ans. C'est un travail de dimensionnement, pas de code — et c'est exactement ce qu'on attendra de vous en projet.

✓ terminé
Quiz

Quiz — Énergie

Jour 3 · Énergie, sécurité et assemblage · 6 min

1. Dans le calcul ci-dessus, quel poste domine ?

2. Vous doublez l'intervalle entre deux réveils. Quel effet ?

3. Que conserve le deep sleep de l'ESP32 ?

✓ terminé
Travaux pratiques

TP 5 — Dormir et se souvenir

Jour 3 · Énergie, sécurité et assemblage · 1 h

Mettre l'objet en sommeil profond et conserver son état d'un réveil à l'autre.

Limite du simulateur

Wokwi simule le cycle de sommeil et le redémarrage, mais ne mesure pas la consommation. Vous vérifierez la logique ici, et calculerez l'énergie avec les valeurs constructeur de la leçon.

  1. Écrivez un firmware qui compte ses réveils. Notez RTC_DATA_ATTR : c'est ce qui place la variable dans la mémoire qui survit au sommeil :
    RTC_DATA_ATTR int nbReveils = 0;
    RTC_DATA_ATTR float mesures[4];
    
    #define uS_PAR_S 1000000ULL
    #define DUREE_SOMMEIL 10          // 10 s pour le TP, 900 en production
    
    void setup() {
      Serial.begin(115200);
      delay(200);
      nbReveils++;
      Serial.printf("reveil numero %d\n", nbReveils);
    
      float v = analogRead(34) * 3.3 / 4095.0;
      mesures[(nbReveils - 1) % 4] = v;
      Serial.printf("mesure %.2f V\n", v);
    
      if (nbReveils % 4 == 0) {
        Serial.print("lot a emettre :");
        for (int i = 0; i < 4; i++) Serial.printf(" %.2f", mesures[i]);
        Serial.println();
      }
    
      esp_sleep_enable_timer_wakeup(DUREE_SOMMEIL * uS_PAR_S);
      Serial.println("dodo");
      esp_deep_sleep_start();
    }
    
    void loop() { }   // jamais atteint : le reveil repart de setup()
  2. Lancez et observez plusieurs cycles. Le compteur s'incrémente alors que le programme repart de setup() à chaque fois : c'est la mémoire RTC qui travaille.
  3. Retirez RTC_DATA_ATTR devant nbReveils et relancez. Le compteur reste bloqué à 1 : la variable ordinaire ne survit pas.
  4. Notez le motif de groupement : quatre mesures gardées en mémoire, une seule émission. C'est la troisième optimisation de la leçon, en pratique.
  5. Reprenez le calcul d'autonomie de la leçon avec vos propres hypothèses : durée de réveil, intervalle, groupement. Cherchez la combinaison qui atteint cinq ans sur 3 000 mAh, et justifiez-la.
  6. Vérifiez la cohérence de votre solution : un intervalle de six heures atteindrait les cinq ans, mais Thermeo veut détecter un problème de chauffage. Quel compromis retenez-vous ?
Questions de réflexion — à préparer par écrit
  • Pourquoi le programme repart-il de setup() et non de loop() ?
  • Quelle taille fait la mémoire RTC, et que ne peut-on pas y mettre ?
  • Le groupement retarde la détection d'un incident. Comment concilier les deux ?
✓ terminé
Leçon

Sécuriser et mettre à jour l'objet

Jour 3 · Énergie, sécurité et assemblage · 20 min

Au module M1, vous avez sécurisé le broker. Reste l'autre bout de la chaîne : l'objet lui-même.

TLS sur un microcontrôleur

L'ESP32 sait faire du TLS, mais le coût est réel : la poignée de main consomme de la mémoire et allonge le temps de réveil — donc l'énergie.

PosteImpact
MémoireUne session TLS occupe 20 à 40 Ko de RAM sur les 520 disponibles
TempsLa poignée de main ajoute 1 à 3 s au réveil — le poste dominant du budget
StockageLe certificat de l'autorité doit être embarqué dans le firmware
La parade : la reprise de session

TLS permet de reprendre une session précédente sans refaire toute la poignée de main. En stockant le ticket en mémoire RTC, un capteur qui se réveille toutes les quinze minutes économise l'essentiel du coût. C'est exactement le genre d'optimisation qui décide de l'autonomie.

La mise à jour à distance

Un parc de cent capteurs sur des toits ne se met pas à jour à la main. L'OTAover the air — est indispensable, et c'est aussi la plus grosse porte d'entrée d'un objet connecté.

Trois exigences non négociables :

  1. Signature du firmware. L'objet vérifie que la mise à jour vient bien de vous. Sans cela, quiconque atteint l'objet peut y installer son propre code.
  2. Double partition. On écrit dans la partition inactive, on bascule au redémarrage. Une coupure pendant le transfert laisse l'ancienne version intacte.
  3. Retour arrière automatique. Si la nouvelle version ne confirme pas son bon démarrage, l'objet repart sur l'ancienne.
Le scénario à éviter

Une mise à jour non signée, poussée sans double partition, sur cent capteurs simultanément. Une erreur dans le firmware et le parc entier devient inaccessible — il faut aller rechercher chaque objet physiquement.

La règle de terrain : déployer par vagues. Un objet, puis dix, puis le reste.

✓ terminé
Travaux pratiques

TP 6 — Le nœud complet

Jour 3 · Énergie, sécurité et assemblage · 1 h 30

Assembler acquisition, filtrage, décision, sommeil et émission sécurisée.

  1. Vous assemblez maintenant tout le module en un seul firmware. C'est le livrable de M2.
  2. Reprenez le montage ESP32 + DHT22 + potentiomètre, et le broker sécurisé de M1.
  3. Structurez le firmware selon la séquence de réveil :
    // 1. reveil -> lire le capteur
    // 2. filtrer (exponentiel, etat conserve en RAM RTC)
    // 3. decider : variation, battement ou plafond ?
    // 4. si emission : Wi-Fi, TLS, MQTT publish, statut en-ligne retenu
    // 5. rendormir
    
    RTC_DATA_ATTR float etatFiltre = 0;
    RTC_DATA_ATTR float derniereEmise = -999;
    RTC_DATA_ATTR int cyclesSansEmission = 0;
  4. Le testament MQTT vu en M1 pose ici une vraie question : un objet qui dort se déconnecte proprement à chaque cycle, donc le testament ne se déclenche pas. Comment détecter alors qu'il est mort ? Traitez ce point explicitement dans votre rendu.
  5. Mesurez sur dix cycles : nombre de mesures, nombre d'émissions, temps de réveil moyen.
  6. Vérifiez côté broker que les messages arrivent bien, avec les ACL de M1 actives.
  7. Rédigez une note d'une page : votre dimensionnement énergétique, les paramètres retenus et leur justification, et la réponse à la question du testament.
Questions de réflexion — à préparer par écrit
  • Un objet qui dort ne peut pas recevoir de commande. Comment lui transmettre une nouvelle consigne ?
  • Où placeriez-vous la reprise de session TLS dans votre séquence de réveil ?
  • Que faudrait-il changer pour passer ce nœud sur LoRaWAN plutôt que Wi-Fi ?
✓ terminé
Point de contrôle

Point de contrôle — fin du module M2

Jour 3 · Énergie, sécurité et assemblage · 20 min

Vérifiez avant de continuer
Le sommeil profond fonctionne et mon compteur survit en mémoire RTC
J'ai vérifié qu'une variable ordinaire ne survit pas au sommeil
Mon calcul d'autonomie atteint cinq ans et je sais le justifier
Mon nœud complet mesure, filtre, décide, émet et se rendort
J'ai chiffré le rapport mesures / émissions sur dix cycles
J'ai traité la question du testament sur un objet qui dort
Je sais expliquer les trois exigences d'une mise à jour OTA sûre
Ma note de dimensionnement est rédigée
Revue de fin de module — lundi 10 août, 15 h 00

Votre encadrant vous fera dérouler le nœud complet et défendre votre dimensionnement. Le calcul d'autonomie est le cœur de l'évaluation : c'est ce qui distingue un firmware qui marche d'un capteur déployable.

Le module M3 enchaîne mardi 11 : vos données quitteront enfin l'objet pour une plateforme cloud.

✓ terminé

Mon avancement

Signature d'émargement

Demander de l'aide à votre encadrant

Étape concernée :

Avant d'envoyer

Cherchez seul pendant 30 minutes et notez ce que vous avez tenté. Ce que vous avez essayé fait partie de ce que vous présentez — c'est ce qui distingue l'autonomie de l'abandon.