diff --git a/include/config.h b/include/config.h index 04d0f93..a2e8c10 100644 --- a/include/config.h +++ b/include/config.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include // ── Constantes matérielles ────────────────────────────────────────── #define ONE_WIRE_BUS 4 // GPIO 4 — bus OneWire DS18B20 @@ -57,8 +59,11 @@ struct NetworkStatus { }; // ── Déclarations extern (définies dans main.cpp) ──────────────────── -extern SondeConfig sondesConfig[NB_SONDES]; -extern SondeEtat sondesEtat[NB_SONDES]; -extern PointHistorique historique[HIST_TAILLE]; -extern uint16_t histIdx; -extern NetworkStatus netStatus; +extern SondeConfig sondesConfig[NB_SONDES]; +extern SondeEtat sondesEtat[NB_SONDES]; +extern PointHistorique historique[HIST_TAILLE]; +extern uint16_t histIdx; +extern NetworkStatus netStatus; +// Mutex FreeRTOS protégeant l'accès concurrent au buffer historique +// (Core 0 : callbacks AsyncWebServer vs Core 1 : loop/sensors_update) +extern SemaphoreHandle_t xHistMutex; diff --git a/src/main.cpp b/src/main.cpp index f37d8d4..64513be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,19 +4,22 @@ #include "sensors.h" #include "web_server.h" -SondeConfig sondesConfig[NB_SONDES] = { +SondeConfig sondesConfig[NB_SONDES] = { { "T°C Ext", "maison/jardin/ext/temperature", 60000, 0.2f }, { "T°C Serre", "maison/jardin/serre/temperature", 60000, 0.1f }, { "T°C Sol", "maison/jardin/sol/temperature", 60000, 0.1f }, }; -SondeEtat sondesEtat[NB_SONDES] = {}; -PointHistorique historique[HIST_TAILLE] = {}; -uint16_t histIdx = 0; -NetworkStatus netStatus = {}; +SondeEtat sondesEtat[NB_SONDES] = {}; +PointHistorique historique[HIST_TAILLE] = {}; +uint16_t histIdx = 0; +NetworkStatus netStatus = {}; +SemaphoreHandle_t xHistMutex = nullptr; void setup() { Serial.begin(115200); - Serial.println("[BOOT] esp_jardin démarrage..."); + delay(500); + Serial.println("\n[BOOT] esp_jardin v1.0 — démarrage..."); + xHistMutex = xSemaphoreCreateMutex(); network_init(); sensors_init(); web_server_init(); diff --git a/src/sensors.cpp b/src/sensors.cpp index 785c98b..293118c 100644 --- a/src/sensors.cpp +++ b/src/sensors.cpp @@ -53,12 +53,15 @@ bool sensors_update() { } } - // Enregistrement dans le buffer circulaire - historique[histIdx].timestamp = maintenant; - for (uint8_t i = 0; i < NB_SONDES; i++) { - historique[histIdx].temps[i] = sondesEtat[i].tempActuelle; // NAN si erreur + // Enregistrement dans le buffer circulaire (protégé contre Core 0) + if (xSemaphoreTake(xHistMutex, pdMS_TO_TICKS(10)) == pdTRUE) { + historique[histIdx].timestamp = maintenant; + for (uint8_t i = 0; i < NB_SONDES; i++) { + historique[histIdx].temps[i] = sondesEtat[i].tempActuelle; + } + histIdx = (histIdx + 1) % HIST_TAILLE; + xSemaphoreGive(xHistMutex); } - histIdx = (histIdx + 1) % HIST_TAILLE; return true; // nouvelle mesure disponible } diff --git a/src/web_server.cpp b/src/web_server.cpp index 77d7574..fa7c55c 100644 --- a/src/web_server.cpp +++ b/src/web_server.cpp @@ -32,19 +32,22 @@ static String _buildJsonSondes() { static String _buildJsonHistory() { JsonDocument doc; JsonArray arr = doc.to(); - for (uint16_t i = 0; i < HIST_TAILLE; i++) { - uint16_t idx = (histIdx + i) % HIST_TAILLE; - if (historique[idx].timestamp == 0) continue; - JsonObject pt = arr.add(); - pt["ts"] = historique[idx].timestamp; - JsonArray t = pt["t"].to(); - for (uint8_t j = 0; j < NB_SONDES; j++) { - if (isnan(historique[idx].temps[j])) { - t.add(nullptr); - } else { - t.add(String(historique[idx].temps[j], 1)); + if (xSemaphoreTake(xHistMutex, pdMS_TO_TICKS(50)) == pdTRUE) { + for (uint16_t i = 0; i < HIST_TAILLE; i++) { + uint16_t idx = (histIdx + i) % HIST_TAILLE; + if (historique[idx].timestamp == 0) continue; + JsonObject pt = arr.add(); + pt["ts"] = historique[idx].timestamp; + JsonArray t = pt["t"].to(); + for (uint8_t j = 0; j < NB_SONDES; j++) { + if (isnan(historique[idx].temps[j])) { + t.add(nullptr); + } else { + t.add(String(historique[idx].temps[j], 1)); + } } } + xSemaphoreGive(xHistMutex); } String out; serializeJson(doc, out); @@ -61,11 +64,12 @@ static void _onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client, } void web_server_init() { - if (!LittleFS.begin()) { - Serial.println("[FS] Erreur montage LittleFS !"); - return; + bool fsOk = LittleFS.begin(); + if (!fsOk) { + Serial.println("[FS] Erreur montage LittleFS — interface web indisponible, API REST active"); + } else { + Serial.println("[FS] LittleFS monté"); } - Serial.println("[FS] LittleFS monté"); _ws.onEvent(_onWsEvent); _server.addHandler(&_ws); @@ -123,8 +127,9 @@ void web_server_init() { } ); - // Servir index.html depuis LittleFS - _server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); + if (fsOk) { + _server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); + } _server.begin(); Serial.println("[HTTP] Serveur web démarré sur port 80");