Files
esp_jardin/plan_corrections.md
T
2026-05-24 13:05:18 +02:00

6.8 KiB

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 :

extern DeviceAddress sondesAddr[NB_SONDES];

src/sensors.cpp — dans sensors_init(), scanner et mémoriser les adresses :

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 :

// 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 :

// 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() :

_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() :

// 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() :

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 :

void web_server_update(); // à appeler dans loop()

web_server.cpp — remplacer le delay par un flag :

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() :

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 :

#include <time.h>

// 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 :

// 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