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é.
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 relationnelle | Base de séries temporelles | |
|---|---|---|
| Écriture | Index à maintenir à chaque insertion | Optimisée pour l'ajout en fin de série |
| Compression | Générique | Exploite la régularité : facteur 10 à 20 courant |
| Requête « moyenne par heure » | À écrire à la main | Native, en une fonction |
| Suppression du vieux | DELETE coûteux | Politique de rétention automatique |
| Agrégats permanents | Vues matérialisées à gérer | Tâches d'agrégation intégrées |
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.
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.
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ément | Rôle | Indexé ? |
|---|---|---|
| measurement | Le nom de la série — l'équivalent d'une table | oui |
| tags | Ce qui identifie la source : site, étage, capteur | oui |
| fields | Les valeurs mesurées : température, humidité | non |
| timestamp | L'instant de la mesure | oui, 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.
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.
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.
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 ?
TP 1 — Monter la base
Jour 1 · Du broker à la base · 1 h
Démarrer InfluxDB, écrire des points à la main et les relire.
Docker, et votre broker Mosquitto de M1 toujours en service.
- 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 - Ouvrez
http://localhost:8086et connectez-vous. Notez la rétention de 7 jours déclarée à la création du bucket. - Dans l'interface, allez dans Load Data → API Tokens et copiez le jeton administrateur. Vous en aurez besoin partout.
- É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' - Vérifiez dans Data Explorer que le point apparaît. Écrivez-en trois autres avec des capteurs et des sites différents.
- 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' - 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.
- 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 ?
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.
- 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.
- Créez
telegraf.conf. Notez letopic_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" - 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 - Vérifiez les journaux — c'est là que se voient les erreurs de connexion :
docker logs -f telegraf-thermeo - Relancez votre
capteur.pyde M1. Après quelques secondes, les points apparaissent dans Data Explorer, correctement étiquetés par site, étage et capteur. - 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.
- 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.
- Pourquoi
host.docker.internalplutôt quelocalhostdans 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 ?
Point de contrôle — fin du jour 1
Jour 1 · Du broker à la base · 15 min
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")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
| Fonction | Ce qu'elle donne | Quand l'utiliser |
|---|---|---|
mean | La moyenne de la fenêtre | Grandeur continue : température |
last | La dernière valeur | État courant, tableau de bord |
max / min | Les extrêmes | Détection de dépassement |
count | Le nombre de points | Vérifier qu'un capteur émet bien |
spread | Écart entre max et min | Amplitude de variation |
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)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 ?
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.
Travaillez dans le Data Explorer d'InfluxDB, onglet Script Editor. Laissez tourner deux ou trois capteurs pour avoir de la matière.
- É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.
- Écrivez la requête « dernière valeur connue de chaque capteur ». Indice :
last()après ungrouppar capteur. - Écrivez la requête « amplitude de variation par capteur sur 24 h » avec
spread. Quel capteur varie le plus ? - É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 - 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.
- É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
pivotou d'un doublegroup. - Consignez les cinq requêtes commentées dans un fichier
requetes.fluxde votre dépôt.
- 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 ?
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.
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 :
| Bucket | Résolution | Rétention | Sert à |
|---|---|---|---|
releves | brute | 7 jours | Diagnostic d'incident récent |
releves_5m | moyenne 5 min | 90 jours | Analyse mensuelle, tendances |
releves_1h | moyenne horaire | 5 ans | Bilans 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")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.
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.
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.
- 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 - Dans l'interface, allez dans Tasks → Create Task et créez la tâche
vers_5mà partir du script de la leçon. - Laissez tourner quinze minutes avec vos capteurs actifs, puis vérifiez que
releves_5mse remplit. Comparez le nombre de points des deux buckets. - 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") - Enrichissez
vers_5mpour conserver aussi le maximum et le minimum, comme le suggère la leçon. Vérifiez que les trois valeurs coexistent bien. - Provoquez la panne annoncée : désactivez la tâche
vers_5m, laissez tourner, puis constatez quereleves_5ma un trou. Réactivez et vérifiez que le trou ne se comble pas tout seul. - 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 ?
- 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
- Pourquoi cascader depuis
releves_5mplutô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 ?
Point de contrôle — fin du jour 2
Jour 2 · Interroger et faire durer · 15 min
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.
| Emplacement | Latence | Ce qu'il peut décider | Vu en |
|---|---|---|---|
| Dans l'objet | immédiate | Seuil simple sur sa propre mesure | M2 |
| Dans le moteur de règles | quelques secondes | Corrélation entre capteurs, conditions composées | M3 |
| Dans l'application | à la consultation | Analyse, tendances, rapports | M4 |
« 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.
| Bloc | Rôle |
|---|---|
mqtt in | S'abonne à un topic |
switch | Aiguille selon une condition |
function | Du JavaScript quand les blocs ne suffisent pas |
influxdb out | Écrit dans la base |
mqtt out | Republie — par exemple une commande vers un actionneur |
debug | Affiche, pour mettre au point |
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é.
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.
- 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 - Ouvrez
http://localhost:1880. Installez le nœud InfluxDB par Menu → Manage palette → Install, modulenode-red-contrib-influxdb. - Construisez un premier flux :
mqtt insurthermeo/+/+/+/temperature→debug. Vérifiez que les messages défilent. - Ajoutez un nœud
functionqui 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; - Ajoutez un
switchqui ne laisse passer quemsg.valeur > 24, puis unmqtt outqui republie surthermeo/alertes/temperature-haute. - Abonnez-vous à ce topic d'alerte depuis un terminal et faites monter la valeur d'un capteur. L'alerte doit apparaître.
- 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 - Faites osciller la valeur autour de 24 et vérifiez qu'une seule alarme part, comme au TP 4 de M2.
- 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.
- Exportez votre flux en JSON et versionnez-le dans votre dépôt.
- 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 ?
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.
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
| Brique | Ce qu'elle fait | Votre équivalent local |
|---|---|---|
| Registre d'appareils | Chaque objet est déclaré avec son certificat et ses attributs | Votre fichier ACL et vos certificats X.509 de M1 |
| Broker managé | MQTT à l'échelle, sans serveur à exploiter | Votre Mosquitto |
| Moteur de règles | Route les messages vers des services selon une requête de type SQL | Node-RED |
| Jumeau numérique | État désiré et état constaté de chaque objet, synchronisés | vous 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.
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ère | Managé | Auto-hébergé |
|---|---|---|
| Mise en service | quelques heures | quelques jours |
| Exploitation | prise en charge | à votre charge : sauvegardes, mises à jour, astreinte |
| Coût à 10 objets | quelques euros par mois | un serveur, donc plus cher |
| Coût à 100 000 objets | significatif, et croissant | amorti |
| Dépendance | forte — les données et les formats sont chez le fournisseur | aucune |
| Souveraineté | selon la région et le fournisseur | totale |
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.
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é ?
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.
- Vous assemblez maintenant tout : nœud de M2 → broker sécurisé de M1 → Telegraf → InfluxDB → Node-RED. C'est le livrable du module.
- Vérifiez que chaque maillon fonctionne isolément, puis lancez l'ensemble avec au moins trois capteurs sur deux sites.
- Rédigez un
docker-compose.ymlqui 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 - Testez la reproductibilité :
docker compose down -vpuisdocker compose up -d. Tout doit repartir, y compris les buckets et les tâches — sinon documentez ce qui manque. - 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. - 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é.
- 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 ?
Point de contrôle — fin du module M3
Jour 3 · Règles et plateformes · 20 min
docker compose updown -v, tout repart — ou j'ai documenté ce qui manqueVotre 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.