1 nouveauté hors suivi
Leçon

Pourquoi pas une base classique

Jour 1 · Du broker à la base · 20 min

Vos relevés se perdent. Le broker les distribue puis les oublie — il ne stocke rien. Il faut donc une base, et le premier réflexe serait PostgreSQL ou MySQL. C'est jouable, mais mal adapté.

Nœud M2 Broker M1 Ingestion Telegraf InfluxDB séries temporelles Règles Node-RED Ce que vous construisez en M3 La visualisation viendra en M4
La chaîne complète. M1 a posé le broker, M2 le nœud ; M3 ajoute l'ingestion, le stockage et les règles.

Ce qu'une série temporelle a de particulier

Une donnée de capteur a trois traits que les bases relationnelles ne prévoient pas :

  • Elle arrive toujours en fin de série. On insère au présent, on ne modifie presque jamais le passé.
  • Elle est massive et répétitive. Cent capteurs à une mesure par minute font 52 millions de lignes par an, dont la plupart se ressemblent.
  • Elle perd de la valeur en vieillissant. La température d'il y a deux ans à la seconde près n'intéresse personne ; sa moyenne horaire, oui.
Base relationnelleBase de séries temporelles
ÉcritureIndex à maintenir à chaque insertionOptimisée pour l'ajout en fin de série
CompressionGénériqueExploite la régularité : facteur 10 à 20 courant
Requête « moyenne par heure »À écrire à la mainNative, en une fonction
Suppression du vieuxDELETE coûteuxPolitique de rétention automatique
Agrégats permanentsVues matérialisées à gérerTâches d'agrégation intégrées
Deux candidats sérieux

InfluxDB — base dédiée, langage propre, écosystème IoT fourni. C'est celle que nous utiliserons.
TimescaleDB — extension de PostgreSQL : on garde SQL et l'outillage relationnel, avec les optimisations séries temporelles par-dessus. Excellent choix si l'équipe connaît déjà PostgreSQL.

Ne surdimensionnez pas

Pour dix capteurs et un an de données, PostgreSQL nu convient très bien. La base de séries temporelles se justifie à partir du moment où le volume ou la fréquence deviennent un problème — pas par principe.

✓ terminé
Leçon

Le modèle de données d'InfluxDB

Jour 1 · Du broker à la base · 25 min

InfluxDB ne raisonne pas en tables et colonnes. Un point se compose de quatre éléments, et bien les distinguer conditionne les performances de tout le système.

thermeo,site=lyon,etage=etage1,capteur=capt-01 temperature=21.4,humidite=48 1723449600
└──┬───┘ └──────────────── tags ────────────────┘ └────── fields ──────┘ └── temps ──┘
 measurement
ÉlémentRôleIndexé ?
measurementLe nom de la série — l'équivalent d'une tableoui
tagsCe qui identifie la source : site, étage, capteuroui
fieldsLes valeurs mesurées : température, humiditénon
timestampL'instant de la mesureoui, c'est la clé

La distinction qui compte

Les tags sont indexés, les fields ne le sont pas. On filtre donc sur des tags, on calcule sur des fields.

L'erreur qui tue une base InfluxDB

Mettre une valeur qui change tout le temps dans un tag. Chaque combinaison de tags distincte crée une série, et l'index les garde toutes en mémoire.

Un tag temperature=21.4 créerait une série par valeur mesurée : des millions de séries, et la base s'écroule. C'est ce qu'on appelle l'explosion de cardinalité, et c'est la panne numéro un d'InfluxDB en production.

Règle pratique

  • Un tag répond à « d'où vient cette mesure ? » — il prend un nombre fini et stable de valeurs. Site, étage, identifiant de capteur, type d'appareil.
  • Un field répond à « que vaut-elle ? » — il varie librement. Température, humidité, tension de pile, compteur.
Le test

Demandez-vous : « vais-je un jour écrire WHERE ceci = cela dessus ? » Si oui, c'est un tag. Si vous voulez en faire une moyenne, c'est un field.

Buckets et rétention

Les points vivent dans un bucket, qui porte une durée de conservation. Passé ce délai, InfluxDB supprime les points automatiquement — pas de tâche de ménage à écrire. Vous exploiterez cela au jour 2.

✓ terminé
Quiz

Quiz — Modèle de données

Jour 1 · Du broker à la base · 8 min

1. Vous voulez pouvoir filtrer par étage. etage doit être :

2. Pourquoi ne jamais mettre la valeur mesurée dans un tag ?

3. Dix capteurs, une mesure par minute, un an. Combien de points ?

4. Que fait la durée de rétention d'un bucket ?

✓ terminé
Travaux pratiques

TP 1 — Monter la base

Jour 1 · Du broker à la base · 1 h

Démarrer InfluxDB, écrire des points à la main et les relire.

Prérequis

Docker, et votre broker Mosquitto de M1 toujours en service.

  1. Démarrez InfluxDB en conteneur, avec sa configuration initiale :
    docker run -d --name influx-thermeo \
      -p 8086:8086 \
      -e DOCKER_INFLUXDB_INIT_MODE=setup \
      -e DOCKER_INFLUXDB_INIT_USERNAME=admin \
      -e DOCKER_INFLUXDB_INIT_PASSWORD=thermeo2026 \
      -e DOCKER_INFLUXDB_INIT_ORG=thermeo \
      -e DOCKER_INFLUXDB_INIT_BUCKET=releves \
      -e DOCKER_INFLUXDB_INIT_RETENTION=7d \
      influxdb:2.7
  2. Ouvrez http://localhost:8086 et connectez-vous. Notez la rétention de 7 jours déclarée à la création du bucket.
  3. Dans l'interface, allez dans Load Data → API Tokens et copiez le jeton administrateur. Vous en aurez besoin partout.
  4. Écrivez un premier point en ligne de commande. Respectez la syntaxe : tags collés au measurement par des virgules, espace, puis fields :
    TOKEN="<votre-jeton>"
    
    curl -s -X POST "http://localhost:8086/api/v2/write?org=thermeo&bucket=releves&precision=s" \
      -H "Authorization: Token $TOKEN" \
      --data-binary 'thermeo,site=lyon,etage=etage1,capteur=capt-01 temperature=21.4'
  5. Vérifiez dans Data Explorer que le point apparaît. Écrivez-en trois autres avec des capteurs et des sites différents.
  6. Faites délibérément l'erreur de cardinalité : écrivez un point où la température est un tag, puis regardez le nombre de séries créées :
    # a NE PAS reproduire en production
    curl -s -X POST "http://localhost:8086/api/v2/write?org=thermeo&bucket=releves" \
      -H "Authorization: Token $TOKEN" \
      --data-binary 'mauvais,capteur=capt-01,temperature=21.4 valeur=1'
  7. Répétez avec cinq températures différentes et comptez les séries dans Data Explorer. Cinq séries pour cinq mesures — extrapolez à un an de relevés et consignez le chiffre.
Questions de réflexion — à préparer par écrit
  • Combien de séries votre schéma correct crée-t-il pour cent capteurs sur trois sites ?
  • Que se passera-t-il dans sept jours pour les points écrits aujourd'hui ?
✓ terminé
Travaux pratiques

TP 2 — Brancher le broker sur la base

Jour 1 · Du broker à la base · 1 h 15

Faire couler les messages MQTT vers InfluxDB, automatiquement et en continu.

  1. Il faut un pont entre le broker et la base. Telegraf fait cela sans une ligne de code : il s'abonne à MQTT et écrit dans InfluxDB.
  2. Créez telegraf.conf. Notez le topic_parsing : c'est lui qui transforme le chemin du topic en tags — exactement la convention posée en M1 :
    [[inputs.mqtt_consumer]]
      servers = ["tcp://host.docker.internal:1883"]
      topics = ["thermeo/+/+/+/temperature", "thermeo/+/+/+/humidite"]
      data_format = "value"
      data_type = "float"
    
      [[inputs.mqtt_consumer.topic_parsing]]
        topic = "thermeo/+/+/+/+"
        measurement = "_/_/_/_/measurement"
        tags = "_/site/etage/capteur/_"
    
    [[outputs.influxdb_v2]]
      urls = ["http://host.docker.internal:8086"]
      token = "$INFLUX_TOKEN"
      organization = "thermeo"
      bucket = "releves"
  3. Démarrez Telegraf :
    docker run -d --name telegraf-thermeo \
      -e INFLUX_TOKEN="<votre-jeton>" \
      -v "$(pwd)/telegraf.conf":/etc/telegraf/telegraf.conf:ro \
      --add-host=host.docker.internal:host-gateway \
      telegraf:1.30
  4. Vérifiez les journaux — c'est là que se voient les erreurs de connexion :
    docker logs -f telegraf-thermeo
  5. Relancez votre capteur.py de M1. Après quelques secondes, les points apparaissent dans Data Explorer, correctement étiquetés par site, étage et capteur.
  6. Vérifiez le mapping : les tags doivent venir du topic, pas être écrits en dur. Lancez un second capteur sur un autre étage et confirmez que les deux séries se distinguent.
  7. Coupez Telegraf trente secondes pendant que le capteur publie, puis relancez-le. Les messages émis pendant la coupure sont perdus — sauf si vous avez prévu quelque chose. Reliez ce constat à la session persistante vue en M1 et proposez une correction.
Questions de réflexion — à préparer par écrit
  • Pourquoi host.docker.internal plutôt que localhost dans la configuration de Telegraf ?
  • Le jeton InfluxDB est passé en variable d'environnement. Pourquoi pas dans le fichier ?
  • Telegraf est un point de passage unique. Quelle conséquence, et comment y remédier ?
✓ terminé
Point de contrôle

Point de contrôle — fin du jour 1

Jour 1 · Du broker à la base · 15 min

Vérifiez avant de continuer
InfluxDB tourne et je sais y écrire un point à la main
Je distingue tag et field, et je sais justifier chaque choix de mon schéma
J'ai provoqué une explosion de cardinalité et chiffré son ampleur
Telegraf achemine les messages MQTT vers la base, sans code
Les tags proviennent du topic et non d'une valeur écrite en dur
J'ai constaté la perte de messages pendant une coupure de Telegraf
✓ terminé
Leçon

Interroger le temps

Jour 2 · Interroger et faire durer · 25 min

Une base de séries temporelles ne s'interroge pas comme une base relationnelle. On ne demande pas « les lignes où… », on demande « l'évolution de… sur… agrégée par… ».

La structure d'une requête Flux

Flux est le langage d'InfluxDB 2. Une requête est un tuyau : chaque étape reçoit le résultat de la précédente.

from(bucket: "releves")
  |> range(start: -1h)                                   // fenêtre de temps
  |> filter(fn: (r) => r._measurement == "temperature")   // quelle série
  |> filter(fn: (r) => r.site == "lyon")                  // filtre sur un tag
  |> aggregateWindow(every: 5m, fn: mean)                 // moyenne par tranche de 5 min
  |> yield(name: "moyennes")
range() est obligatoire, et ce n'est pas une contrainte gratuite

Sans fenêtre de temps, la requête balaierait toute l'histoire de la base. InfluxDB l'exige pour éviter qu'une requête distraite ne mette le serveur à genoux.

Les fonctions d'agrégation

FonctionCe qu'elle donneQuand l'utiliser
meanLa moyenne de la fenêtreGrandeur continue : température
lastLa dernière valeurÉtat courant, tableau de bord
max / minLes extrêmesDétection de dépassement
countLe nombre de pointsVérifier qu'un capteur émet bien
spreadÉcart entre max et minAmplitude de variation
La subtilité de aggregateWindow

Il découpe la plage en tranches régulières et applique la fonction à chacune. every: 5m sur une heure produit douze points, quel que soit le nombre de mesures brutes. C'est ce qui rend un graphique lisible quel que soit le zoom.

Comparer plusieurs capteurs

Par défaut, Flux garde les séries séparées : une courbe par combinaison de tags. Pour les regrouper, on redéfinit le groupement.

from(bucket: "releves")
  |> range(start: -24h)
  |> filter(fn: (r) => r._measurement == "temperature")
  |> group(columns: ["site"])            // une courbe par site, capteurs confondus
  |> aggregateWindow(every: 1h, fn: mean)
✓ terminé
Quiz

Quiz — Requêtes

Jour 2 · Interroger et faire durer · 7 min

1. Pourquoi range() est-il obligatoire dans une requête Flux ?

2. Vous voulez l'état courant de chaque capteur pour un tableau de bord. Quelle fonction ?

3. aggregateWindow(every: 5m, fn: mean) sur une plage d'une heure produit :

4. Comment obtenir une seule courbe par site, tous capteurs confondus ?

✓ terminé
Travaux pratiques

TP 3 — Faire parler les données

Jour 2 · Interroger et faire durer · 1 h

Écrire les requêtes dont un exploitant a réellement besoin.

Méthode

Travaillez dans le Data Explorer d'InfluxDB, onglet Script Editor. Laissez tourner deux ou trois capteurs pour avoir de la matière.

  1. Écrivez la requête « température moyenne par tranche de 5 minutes sur la dernière heure, pour le site de Lyon », en repartant de l'exemple de la leçon.
  2. Écrivez la requête « dernière valeur connue de chaque capteur ». Indice : last() après un group par capteur.
  3. Écrivez la requête « amplitude de variation par capteur sur 24 h » avec spread. Quel capteur varie le plus ?
  4. Écrivez la requête qui détecte un capteur muet : ceux dont le nombre de points sur les dix dernières minutes est nul ou anormalement bas. Ossature :
    from(bucket: "releves")
      |> range(start: -10m)
      |> filter(fn: (r) => r._measurement == "temperature")
      |> group(columns: ["capteur"])
      |> count()
      |> filter(fn: (r) => r._value < 5)     // seuil a ajuster selon votre cadence
  5. Coupez un capteur et vérifiez que votre requête le fait bien remonter. Comparez cette approche au testament MQTT de M1 : les deux détectent une panne, mais pas de la même façon ni au même moment.
  6. Écrivez enfin la requête « écart entre le capteur le plus chaud et le plus froid de chaque site ». Elle est plus difficile : cherchez du côté de pivot ou d'un double group.
  7. Consignez les cinq requêtes commentées dans un fichier requetes.flux de votre dépôt.
Questions de réflexion — à préparer par écrit
  • Détection par requête ou par testament : quels avantages respectifs, et lequel réagit le plus vite ?
  • Votre seuil de détection de capteur muet dépend de la cadence d'émission. Comment le rendre robuste au changement de cadence de M2 ?
✓ terminé
Leçon

Ne pas tout garder pour toujours

Jour 2 · Interroger et faire durer · 20 min

Cent capteurs à une mesure par minute, c'est 52 millions de points par an. À la seconde, c'est 3 milliards. Aucune base ne tient ce rythme indéfiniment — et surtout, personne n'en a besoin.

brut · 10 s 7 jours 60 480 points moyenne · 5 min 90 jours 25 920 points moyenne · 1 h 5 ans 43 800 points agrège agrège Plus on remonte dans le temps, moins la résolution fine a de valeur
Trois niveaux de résolution, trois durées de conservation. Le volume total reste maîtrisé.

Le principe

On conserve le détail fin peu de temps, et des agrégats de plus en plus grossiers de plus en plus longtemps. Trois buckets, trois rétentions :

BucketRésolutionRétentionSert à
relevesbrute7 joursDiagnostic d'incident récent
releves_5mmoyenne 5 min90 joursAnalyse mensuelle, tendances
releves_1hmoyenne horaire5 ansBilans annuels, contrats

Les tâches d'agrégation

InfluxDB exécute des tâches périodiques qui lisent un bucket, agrègent et écrivent dans un autre. Une fois en place, tout se fait sans intervention.

option task = {name: "vers_5m", every: 5m}

from(bucket: "releves")
  |> range(start: -task.every)
  |> filter(fn: (r) => r._measurement == "temperature")
  |> aggregateWindow(every: 5m, fn: mean)
  |> to(bucket: "releves_5m", org: "thermeo")
L'ordre des opérations n'est pas négociable

La tâche d'agrégation doit tourner avant que la rétention n'efface les données brutes. Si la rétention est à 7 jours et que la tâche échoue pendant huit jours, les données sont perdues sans recours.

Surveillez l'exécution des tâches : c'est un point de défaillance silencieux.

Ce qu'on perd

Agréger, c'est choisir. Une moyenne horaire efface les pics : si un capteur monte à 45 °C pendant deux minutes, la moyenne de l'heure ne le montrera pas.

La parade

Conserver plusieurs agrégats de la même fenêtre : moyenne et maximum et minimum. Le volume triple, mais reste négligeable face aux données brutes — et on garde la trace des extrêmes, qui sont souvent ce qui intéresse.

✓ terminé
Travaux pratiques

TP 4 — Rétention et agrégats

Jour 2 · Interroger et faire durer · 1 h 15

Mettre en place la cascade de buckets et automatiser l'agrégation.

  1. Créez les deux buckets d'agrégats, avec leurs rétentions :
    docker exec influx-thermeo influx bucket create \
      --name releves_5m --org thermeo --retention 90d
    
    docker exec influx-thermeo influx bucket create \
      --name releves_1h --org thermeo --retention 1825d
  2. Dans l'interface, allez dans Tasks → Create Task et créez la tâche vers_5m à partir du script de la leçon.
  3. Laissez tourner quinze minutes avec vos capteurs actifs, puis vérifiez que releves_5m se remplit. Comparez le nombre de points des deux buckets.
  4. Créez la seconde tâche, qui agrège les 5 minutes en heures. Notez qu'elle lit releves_5m, pas les données brutes — on cascade :
    option task = {name: "vers_1h", every: 1h}
    
    from(bucket: "releves_5m")
      |> range(start: -task.every)
      |> aggregateWindow(every: 1h, fn: mean)
      |> to(bucket: "releves_1h", org: "thermeo")
  5. Enrichissez vers_5m pour conserver aussi le maximum et le minimum, comme le suggère la leçon. Vérifiez que les trois valeurs coexistent bien.
  6. Provoquez la panne annoncée : désactivez la tâche vers_5m, laissez tourner, puis constatez que releves_5m a un trou. Réactivez et vérifiez que le trou ne se comble pas tout seul.
  7. Rédigez la procédure de rattrapage : quelle requête permettrait de reconstruire les agrégats manquants tant que les données brutes existent encore ?
  8. Calculez le volume : combien de points chaque bucket contiendra-t-il à plein régime pour cent capteurs ? Comparez au volume qu'aurait un stockage brut sur cinq ans.
    # a completer dans votre rendu
    # brut 7 j     : 100 capteurs x ... x ...
    # 5 min 90 j   : ...
    # 1 h 5 ans    : ...
    # total        : ... contre ... en tout-brut sur 5 ans
Questions de réflexion — à préparer par écrit
  • Pourquoi cascader depuis releves_5m plutôt que d'agréger les données brutes en horaire directement ?
  • Comment détecter automatiquement qu'une tâche d'agrégation a cessé de tourner ?
  • Quelle rétention retiendriez-vous pour Thermeo, et sur quel argument ?
✓ terminé
Point de contrôle

Point de contrôle — fin du jour 2

Jour 2 · Interroger et faire durer · 15 min

Vérifiez avant de continuer
Mes cinq requêtes Flux fonctionnent et sont commentées dans mon dépôt
Ma requête de détection de capteur muet remonte bien un capteur coupé
Je sais comparer cette détection au testament MQTT de M1
Les trois buckets existent avec leurs rétentions
Mes deux tâches d'agrégation tournent en cascade
Je conserve moyenne, maximum et minimum par fenêtre
J'ai provoqué un trou d'agrégation et rédigé la procédure de rattrapage
Mon calcul de volume est posé et comparé au tout-brut
✓ terminé
Leçon

De la donnée à l'action

Jour 3 · Règles et plateformes · 20 min

Stocker ne sert à rien si personne n'agit. Il manque la brique qui transforme une mesure en décision : le moteur de règles.

Où placer la règle

Vous savez maintenant qu'une décision peut se prendre à trois endroits, et le choix n'est pas indifférent.

EmplacementLatenceCe qu'il peut déciderVu en
Dans l'objetimmédiateSeuil simple sur sa propre mesureM2
Dans le moteur de règlesquelques secondesCorrélation entre capteurs, conditions composéesM3
Dans l'applicationà la consultationAnalyse, tendances, rapportsM4
L'exemple qui départage

« Alerter si la température dépasse 24 °C » — l'objet sait le faire seul.
« Alerter si la température dépasse 24 °C alors que la chaudière est à l'arrêt et qu'aucune fenêtre n'est ouverte » — il faut croiser trois sources, donc un moteur de règles.

Node-RED

Node-RED assemble des traitements par blocs reliés graphiquement. C'est l'outil dominant dans l'IoT pour ce type de règles : on branche une entrée MQTT, un test, une sortie, et c'est en service.

BlocRôle
mqtt inS'abonne à un topic
switchAiguille selon une condition
functionDu JavaScript quand les blocs ne suffisent pas
influxdb outÉcrit dans la base
mqtt outRepublie — par exemple une commande vers un actionneur
debugAffiche, pour mettre au point
La limite de l'outil graphique

Un flux Node-RED de trente blocs devient illisible et se relit mal en revue de code. Il se versionne mal aussi : le format JSON exporté produit des différences peu exploitables.

Node-RED excelle pour le prototypage et les règles simples. Au-delà, écrire un service reste plus maintenable — c'est un arbitrage à assumer, pas une fatalité.

✓ terminé
Travaux pratiques

TP 5 — Une règle qui déclenche

Jour 3 · Règles et plateformes · 1 h 15

Construire une alerte qui croise plusieurs sources et republie une décision.

  1. Démarrez Node-RED :
    docker run -d --name nodered-thermeo \
      -p 1880:1880 \
      --add-host=host.docker.internal:host-gateway \
      nodered/node-red:3.1
  2. Ouvrez http://localhost:1880. Installez le nœud InfluxDB par Menu → Manage palette → Install, module node-red-contrib-influxdb.
  3. Construisez un premier flux : mqtt in sur thermeo/+/+/+/temperaturedebug. Vérifiez que les messages défilent.
  4. Ajoutez un nœud function qui extrait le capteur depuis le topic et convertit la charge utile :
    const p = msg.topic.split('/');
    msg.site = p[1];
    msg.etage = p[2];
    msg.capteur = p[3];
    msg.valeur = parseFloat(msg.payload);
    return msg;
  5. Ajoutez un switch qui ne laisse passer que msg.valeur > 24, puis un mqtt out qui republie sur thermeo/alertes/temperature-haute.
  6. Abonnez-vous à ce topic d'alerte depuis un terminal et faites monter la valeur d'un capteur. L'alerte doit apparaître.
  7. Ajoutez maintenant l'hystérésis vue en M2 — le seuil nu produit une rafale. Utilisez le contexte de flux pour mémoriser l'état :
    const enAlarme = flow.get('alarme_' + msg.capteur) || false;
    if (!enAlarme && msg.valeur > 24.0) {
      flow.set('alarme_' + msg.capteur, true);
      msg.payload = 'ALARME ' + msg.capteur + ' : ' + msg.valeur;
      return msg;
    }
    if (enAlarme && msg.valeur < 23.0) {
      flow.set('alarme_' + msg.capteur, false);
      msg.payload = 'fin alarme ' + msg.capteur;
      return msg;
    }
    return null;   // rien a signaler
  8. Faites osciller la valeur autour de 24 et vérifiez qu'une seule alarme part, comme au TP 4 de M2.
  9. Construisez enfin la règle composée : alerter seulement si la température dépasse 24 °C et que l'humidité du même capteur est inférieure à 40 %. Il faut mémoriser la dernière humidité connue par capteur — c'est l'exercice difficile du TP.
  10. Exportez votre flux en JSON et versionnez-le dans votre dépôt.
Questions de réflexion — à préparer par écrit
  • Pourquoi mémoriser l'état d'alarme par capteur plutôt qu'une variable unique ?
  • Votre règle composée dépend de la dernière humidité connue. Que se passe-t-il si le capteur d'humidité est muet depuis une heure ?
  • Quelle règle mettriez-vous dans l'objet plutôt que dans Node-RED, et pourquoi ?
✓ terminé
Leçon

Les plateformes managées

Jour 3 · Règles et plateformes · 25 min

Vous venez de construire votre plateforme : broker, ingestion, base, règles. AWS IoT Core et Azure IoT Hub proposent la même chose, exploitée pour vous. Il faut savoir arbitrer.

Pourquoi ce module reste en local

Les TP tournent sur une pile conteneurisée parce qu'aucun compte cloud n'est garanti et qu'un parcours ne doit pas dépendre d'un abonnement. Les concepts ci-dessous sont en revanche ceux que vous retrouverez chez tous les fournisseurs — c'est ce qui compte.

Les quatre briques d'une plateforme managée

BriqueCe qu'elle faitVotre équivalent local
Registre d'appareilsChaque objet est déclaré avec son certificat et ses attributsVotre fichier ACL et vos certificats X.509 de M1
Broker managéMQTT à l'échelle, sans serveur à exploiterVotre Mosquitto
Moteur de règlesRoute les messages vers des services selon une requête de type SQLNode-RED
Jumeau numériqueÉtat désiré et état constaté de chaque objet, synchronisésvous n'avez pas d'équivalent

Le jumeau numérique — la brique qui manque

C'est le concept le plus intéressant, et celui que votre maquette ne couvre pas. Le jumeau — device shadow chez AWS — conserve deux états pour chaque objet :

  • L'état constaté, ce que l'objet a rapporté en dernier.
  • L'état désiré, ce qu'on voudrait qu'il soit.

Quand ils diffèrent, la plateforme envoie la consigne à l'objet dès qu'il se reconnecte. Cela résout exactement le problème posé au TP 6 de M2 : comment commander un objet qui dort ? On n'attend pas qu'il écoute — on écrit dans son jumeau, il se synchronise à son réveil.

À retenir même sans AWS

Ce motif — écrire l'état désiré quelque part, laisser l'objet le récupérer à son réveil — se reproduit très bien avec un message MQTT retenu sur un topic de consigne. Vous avez tout ce qu'il faut depuis M1.

Managé ou auto-hébergé

CritèreManagéAuto-hébergé
Mise en servicequelques heuresquelques jours
Exploitationprise en chargeà votre charge : sauvegardes, mises à jour, astreinte
Coût à 10 objetsquelques euros par moisun serveur, donc plus cher
Coût à 100 000 objetssignificatif, et croissantamorti
Dépendanceforte — les données et les formats sont chez le fournisseuraucune
Souverainetéselon la région et le fournisseurtotale
Le critère qu'on oublie

La réversibilité. Migrer cent mille objets d'une plateforme à une autre suppose de reprovisionner chaque certificat et de réécrire chaque règle. Ce coût ne se voit pas au démarrage et devient déterminant à l'échelle — c'est le point à faire figurer dans toute recommandation.

✓ terminé
Quiz

Quiz — Règles et plateformes

Jour 3 · Règles et plateformes · 7 min

1. « Alerter si T > 24 °C alors que la chaudière est à l'arrêt ». Où placer cette règle ?

2. À quoi sert le jumeau numérique ?

3. Quel motif MQTT reproduit l'essentiel d'un jumeau, sans plateforme managée ?

4. Quel critère est le plus souvent négligé dans le choix managé / auto-hébergé ?

✓ terminé
Travaux pratiques

TP 6 — La chaîne complète

Jour 3 · Règles et plateformes · 1 h 30

Assembler le pipeline de bout en bout et instruire le choix de plateforme.

  1. Vous assemblez maintenant tout : nœud de M2 → broker sécurisé de M1 → Telegraf → InfluxDB → Node-RED. C'est le livrable du module.
  2. Vérifiez que chaque maillon fonctionne isolément, puis lancez l'ensemble avec au moins trois capteurs sur deux sites.
  3. Rédigez un docker-compose.yml qui démarre toute la pile en une commande. C'est ce qui rend votre maquette reproductible :
    # services attendus : mosquitto, influxdb, telegraf, nodered
    # volumes pour la configuration et la persistance
    # reseau commun, plus de host.docker.internal
  4. Testez la reproductibilité : docker compose down -v puis docker compose up -d. Tout doit repartir, y compris les buckets et les tâches — sinon documentez ce qui manque.
  5. Mettez en œuvre le motif du jumeau avec ce que vous avez : publiez une consigne en message retenu sur thermeo/lyon/etage1/capt-01/consigne, et faites en sorte que le capteur la lise à son réveil. Reliez cela au TP 6 de M2.
  6. Rédigez une note de deux pages : le schéma de votre architecture, le volume de données attendu à trois ans, et une recommandation managé ou auto-hébergé pour Thermeo, argumentée sur au moins quatre critères dont la réversibilité.
Questions de réflexion — à préparer par écrit
  • Quel maillon de votre chaîne est le plus fragile, et que se passe-t-il s'il tombe ?
  • Combien de temps faudrait-il pour remonter cette pile sur un serveur neuf ?
  • Qu'est-ce qui manque encore pour que Thermeo exploite vraiment ces données ?
✓ terminé
Point de contrôle

Point de contrôle — fin du module M3

Jour 3 · Règles et plateformes · 20 min

Vérifiez avant de continuer
Node-RED déclenche une alerte avec hystérésis, une seule par franchissement
Ma règle composée croise température et humidité du même capteur
Mon flux est exporté et versionné
La pile entière démarre par un seul docker compose up
Après un down -v, tout repart — ou j'ai documenté ce qui manque
Le motif du jumeau fonctionne avec un message retenu de consigne
Ma note d'architecture et ma recommandation sont rédigées
Je sais expliquer où placer une règle : objet, moteur ou application
Revue de fin de module — jeudi 13 août, 15 h 00

Votre encadrant lancera lui-même docker compose up sur votre dépôt. Si la pile ne remonte pas, c'est le premier point à corriger : une maquette non reproductible n'est pas livrable.

M4 enchaîne vendredi 14 : vos données deviendront enfin visibles.

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