# Plan de corrections — esp_jardin Toutes les améliorations identifiées lors de la revue de code, classées par priorité. --- ## ✅ Déjà corrigé dans cette session | Correction | Fichier | Description | |---|---|---| | Race condition historique | `sensors.cpp` | Utilise `tempLues[i]` au lieu de `sondesEtat[i]` dans le buffer historique | | MQTT timeout bloquant | `mqtt_manager.cpp` | `_wifiClient.setTimeout(2000)` — limite le blocage à 2s max | | LWT (Last Will Testament) | `mqtt_manager.cpp` | Le broker publie `offline` automatiquement si l'ESP disparaît | | Heartbeat MQTT | `mqtt_manager.cpp` | Publication `online` toutes les 60s sur `maison/jardin/status` | | Erreurs sonde MQTT | `mqtt_manager.cpp` | Publication `1`/`0` sur `maison/jardin/ext/erreur` au changement d'état | --- ## Corrections restantes ### Tâche 1 — DS18B20 : lecture par adresse ROM (priorité haute) **Problème :** `getTempCByIndex(i)` retourne les capteurs dans l'ordre d'énumération OneWire, qui peut changer si une sonde est débranchée ou remplacée. Cela peut inverser T°C Ext ↔ T°C Sol sans avertissement. **Fichiers :** `include/config.h`, `include/sensors.h`, `src/sensors.cpp` **Changements :** `include/sensors.h` — ajouter la déclaration : ```cpp extern DeviceAddress sondesAddr[NB_SONDES]; ``` `src/sensors.cpp` — dans `sensors_init()`, scanner et mémoriser les adresses : ```cpp DeviceAddress sondesAddr[NB_SONDES] = {}; void sensors_init() { _sensors.begin(); _sensors.setWaitForConversion(false); uint8_t nb = _sensors.getDeviceCount(); Serial.printf("[SONDES] %u capteur(s) détecté(s) sur GPIO %d\n", nb, ONE_WIRE_BUS); for (uint8_t i = 0; i < NB_SONDES; i++) { if (_sensors.getAddress(sondesAddr[i], i)) { Serial.printf("[SONDE %u] Adresse: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", i, sondesAddr[i][0], sondesAddr[i][1], sondesAddr[i][2], sondesAddr[i][3], sondesAddr[i][4], sondesAddr[i][5], sondesAddr[i][6], sondesAddr[i][7]); } else { Serial.printf("[SONDE %u] Adresse introuvable\n", i); } } } ``` Dans la boucle de lecture, remplacer : ```cpp // Avant float t = _sensors.getTempCByIndex(i); // Après float t = _sensors.getTempC(sondesAddr[i]); ``` > **Note :** Les adresses ROM doivent être fixées au premier branchement. Si tu changes l'ordre physique des sondes, il faut reprogrammer la correspondance dans `main.cpp` ou les sauvegarder en NVS. --- ### Tâche 2 — DS18B20 : résolution 11-bit (priorité faible) **Problème :** La résolution par défaut est 12 bits (précision 0,0625°C, conversion 750ms). Pour une station jardin, 11 bits suffisent largement (précision 0,125°C, conversion 375ms). **Fichiers :** `include/config.h`, `src/sensors.cpp` `config.h` — modifier la constante : ```cpp // Avant static const uint32_t CONVERSION_MS = 750; // Après (déplacer dans config.h) #define CONVERSION_MS 375 // 11-bit : 375ms au lieu de 750ms ``` `sensors.cpp` — ajouter dans `sensors_init()` après `_sensors.begin()` : ```cpp _sensors.setResolution(11); // 0.125°C, 375ms — suffisant pour jardin ``` --- ### Tâche 3 — WiFi : RSSI lu trop souvent (priorité faible) **Problème :** `WiFi.RSSI()` est appelé à chaque itération de `loop()` (plusieurs milliers de fois par seconde), alors que la valeur change sur une échelle de secondes. **Fichier :** `src/network.cpp` Remplacer dans `network_update()` : ```cpp // Avant } else { netStatus.rssi = WiFi.RSSI(); } // Après } else { static uint32_t _dernierRssiMs = 0; if (millis() - _dernierRssiMs >= 10000) { netStatus.rssi = WiFi.RSSI(); _dernierRssiMs = millis(); } } ``` --- ### Tâche 4 — WiFi : persistent(false) (priorité faible) **Problème :** Sans `WiFi.persistent(false)`, le SDK ESP32 sauvegarde aussi les credentials en NVS automatiquement, en doublon de notre propre gestion NVS. **Fichier :** `src/network.cpp` Ajouter dans `_demarrerSTA()` avant `WiFi.begin()` : ```cpp WiFi.persistent(false); // on gère la persistance nous-mêmes via Preferences WiFi.begin(_ssidActif, _passActif); ``` --- ### Tâche 5 — Web server : delay() dans callback async (priorité faible) **Problème :** `delay(500)` dans le handler `/api/wifi/connect` bloque la tâche AsyncTCP (Core 0) pendant 500ms avant le redémarrage. **Fichiers :** `include/web_server.h`, `src/web_server.cpp`, `src/main.cpp` `web_server.h` — ajouter la déclaration : ```cpp void web_server_update(); // à appeler dans loop() ``` `web_server.cpp` — remplacer le delay par un flag : ```cpp static bool _redemarrerDemande = false; // Dans le handler POST /api/wifi/connect, remplacer : // delay(500); // ESP.restart(); // Par : req->send(200, "application/json", "{\"ok\":true}"); _redemarrerDemande = true; // Ajouter la fonction : void web_server_update() { if (_redemarrerDemande) { delay(300); // dans loop() : delay() est toléré ESP.restart(); } } ``` `main.cpp` — ajouter dans `loop()` : ```cpp void loop() { network_update(); web_server_update(); // ajouter bool nouvelleMesure = sensors_update(); ... } ``` --- ### Tâche 6 — Historique : timestamps absolus via NTP (priorité optionnelle) **Problème :** Les timestamps sont basés sur `millis()` (ms depuis le démarrage). Après un reboot, ils repartent à 0. L'interface web ne peut pas afficher des heures réelles (ex: "23h15"). **Fichier :** `src/sensors.cpp`, `src/network.cpp` `network.cpp` — synchroniser l'heure NTP après connexion WiFi : ```cpp #include // Dans _configurerMDNS() ou après la connexion WiFi : configTime(3600, 3600, "pool.ntp.org"); // UTC+1, +1h été (à adapter) Serial.println("[NTP] Synchronisation heure..."); ``` `sensors.cpp` — utiliser `time(nullptr)` comme timestamp : ```cpp // Avant historique[histIdx].timestamp = maintenant; // millis() // Après historique[histIdx].timestamp = (uint32_t)time(nullptr); // Unix timestamp ``` `config.h` — adapter le type si nécessaire (uint32_t Unix timestamp est valide jusqu'en 2106). > **Note :** Les graphiques de l'interface web devront adapter l'axe X pour des Unix timestamps plutôt que des ms depuis le boot. --- ## Ordre d'exécution recommandé | Priorité | Tâche | Risque si ignoré | |---|---|---| | 🔴 Haute | Tâche 1 — DS18B20 adresses ROM | Fausses lectures MQTT si sonde déconnectée | | 🟡 Moyenne | Tâche 2 — Résolution 11-bit | Aucun, juste optimisation | | 🟡 Moyenne | Tâche 3 — RSSI throttle | Aucun, CPU légèrement gaspillé | | 🟢 Faible | Tâche 4 — WiFi persistent(false) | Doublon NVS, usure Flash négligeable | | 🟢 Faible | Tâche 5 — delay() async | 500ms de blocage une seule fois (reboot) | | ⚪ Optionnel | Tâche 6 — NTP timestamps | Graphiques sans heure réelle |