fix: mutex FreeRTOS buffer historique, découplage LittleFS/REST
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+10
-5
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/semphr.h>
|
||||||
|
|
||||||
// ── Constantes matérielles ──────────────────────────────────────────
|
// ── Constantes matérielles ──────────────────────────────────────────
|
||||||
#define ONE_WIRE_BUS 4 // GPIO 4 — bus OneWire DS18B20
|
#define ONE_WIRE_BUS 4 // GPIO 4 — bus OneWire DS18B20
|
||||||
@@ -57,8 +59,11 @@ struct NetworkStatus {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ── Déclarations extern (définies dans main.cpp) ────────────────────
|
// ── Déclarations extern (définies dans main.cpp) ────────────────────
|
||||||
extern SondeConfig sondesConfig[NB_SONDES];
|
extern SondeConfig sondesConfig[NB_SONDES];
|
||||||
extern SondeEtat sondesEtat[NB_SONDES];
|
extern SondeEtat sondesEtat[NB_SONDES];
|
||||||
extern PointHistorique historique[HIST_TAILLE];
|
extern PointHistorique historique[HIST_TAILLE];
|
||||||
extern uint16_t histIdx;
|
extern uint16_t histIdx;
|
||||||
extern NetworkStatus netStatus;
|
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;
|
||||||
|
|||||||
+9
-6
@@ -4,19 +4,22 @@
|
|||||||
#include "sensors.h"
|
#include "sensors.h"
|
||||||
#include "web_server.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 Ext", "maison/jardin/ext/temperature", 60000, 0.2f },
|
||||||
{ "T°C Serre", "maison/jardin/serre/temperature", 60000, 0.1f },
|
{ "T°C Serre", "maison/jardin/serre/temperature", 60000, 0.1f },
|
||||||
{ "T°C Sol", "maison/jardin/sol/temperature", 60000, 0.1f },
|
{ "T°C Sol", "maison/jardin/sol/temperature", 60000, 0.1f },
|
||||||
};
|
};
|
||||||
SondeEtat sondesEtat[NB_SONDES] = {};
|
SondeEtat sondesEtat[NB_SONDES] = {};
|
||||||
PointHistorique historique[HIST_TAILLE] = {};
|
PointHistorique historique[HIST_TAILLE] = {};
|
||||||
uint16_t histIdx = 0;
|
uint16_t histIdx = 0;
|
||||||
NetworkStatus netStatus = {};
|
NetworkStatus netStatus = {};
|
||||||
|
SemaphoreHandle_t xHistMutex = nullptr;
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
Serial.begin(115200);
|
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();
|
network_init();
|
||||||
sensors_init();
|
sensors_init();
|
||||||
web_server_init();
|
web_server_init();
|
||||||
|
|||||||
+8
-5
@@ -53,12 +53,15 @@ bool sensors_update() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enregistrement dans le buffer circulaire
|
// Enregistrement dans le buffer circulaire (protégé contre Core 0)
|
||||||
historique[histIdx].timestamp = maintenant;
|
if (xSemaphoreTake(xHistMutex, pdMS_TO_TICKS(10)) == pdTRUE) {
|
||||||
for (uint8_t i = 0; i < NB_SONDES; i++) {
|
historique[histIdx].timestamp = maintenant;
|
||||||
historique[histIdx].temps[i] = sondesEtat[i].tempActuelle; // NAN si erreur
|
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
|
return true; // nouvelle mesure disponible
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-17
@@ -32,19 +32,22 @@ static String _buildJsonSondes() {
|
|||||||
static String _buildJsonHistory() {
|
static String _buildJsonHistory() {
|
||||||
JsonDocument doc;
|
JsonDocument doc;
|
||||||
JsonArray arr = doc.to<JsonArray>();
|
JsonArray arr = doc.to<JsonArray>();
|
||||||
for (uint16_t i = 0; i < HIST_TAILLE; i++) {
|
if (xSemaphoreTake(xHistMutex, pdMS_TO_TICKS(50)) == pdTRUE) {
|
||||||
uint16_t idx = (histIdx + i) % HIST_TAILLE;
|
for (uint16_t i = 0; i < HIST_TAILLE; i++) {
|
||||||
if (historique[idx].timestamp == 0) continue;
|
uint16_t idx = (histIdx + i) % HIST_TAILLE;
|
||||||
JsonObject pt = arr.add<JsonObject>();
|
if (historique[idx].timestamp == 0) continue;
|
||||||
pt["ts"] = historique[idx].timestamp;
|
JsonObject pt = arr.add<JsonObject>();
|
||||||
JsonArray t = pt["t"].to<JsonArray>();
|
pt["ts"] = historique[idx].timestamp;
|
||||||
for (uint8_t j = 0; j < NB_SONDES; j++) {
|
JsonArray t = pt["t"].to<JsonArray>();
|
||||||
if (isnan(historique[idx].temps[j])) {
|
for (uint8_t j = 0; j < NB_SONDES; j++) {
|
||||||
t.add(nullptr);
|
if (isnan(historique[idx].temps[j])) {
|
||||||
} else {
|
t.add(nullptr);
|
||||||
t.add(String(historique[idx].temps[j], 1));
|
} else {
|
||||||
|
t.add(String(historique[idx].temps[j], 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
xSemaphoreGive(xHistMutex);
|
||||||
}
|
}
|
||||||
String out;
|
String out;
|
||||||
serializeJson(doc, out);
|
serializeJson(doc, out);
|
||||||
@@ -61,11 +64,12 @@ static void _onWsEvent(AsyncWebSocket* server, AsyncWebSocketClient* client,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void web_server_init() {
|
void web_server_init() {
|
||||||
if (!LittleFS.begin()) {
|
bool fsOk = LittleFS.begin();
|
||||||
Serial.println("[FS] Erreur montage LittleFS !");
|
if (!fsOk) {
|
||||||
return;
|
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);
|
_ws.onEvent(_onWsEvent);
|
||||||
_server.addHandler(&_ws);
|
_server.addHandler(&_ws);
|
||||||
@@ -123,8 +127,9 @@ void web_server_init() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Servir index.html depuis LittleFS
|
if (fsOk) {
|
||||||
_server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
|
_server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
|
||||||
|
}
|
||||||
|
|
||||||
_server.begin();
|
_server.begin();
|
||||||
Serial.println("[HTTP] Serveur web démarré sur port 80");
|
Serial.println("[HTTP] Serveur web démarré sur port 80");
|
||||||
|
|||||||
Reference in New Issue
Block a user