feat: forecast change log

Record each forecast change (Zambretti letter transition) with a
timestamp into a 24-entry ring buffer, persisted to LittleFS and
restored on boot. New /api/forecasts endpoint and a 'Forecast log'
panel in the web UI (newest first, category colour, timestamp).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 22:40:28 +07:00
co-authored by Claude Opus 4.8
parent f4a9a04207
commit f1fe0b728f
8 changed files with 157 additions and 0 deletions
+18
View File
@@ -3,6 +3,7 @@
#include "state.h"
#include "app_settings.h"
#include "history.h"
#include "flog.h"
#include "forecast.h"
#include "web_page.h"
@@ -47,6 +48,22 @@ static void handleHistory() {
server.send(200, "application/json", out);
}
static void handleForecasts() {
JsonDocument doc;
JsonArray arr = doc.to<JsonArray>();
int n = flogCount();
for (int i = n - 1; i >= 0; i--) { // newest first
FcastEntry e = flogGet(i);
JsonObject o = arr.add<JsonObject>();
o["t"] = e.epoch;
o["cat"] = categoryShort((WxCategory)e.cat);
o["text"] = forecastTextForLetter(e.letter);
}
String out;
serializeJson(doc, out);
server.send(200, "application/json", out);
}
static void handleGetSettings() {
JsonDocument doc;
doc["altitude"] = settings.altitudeM;
@@ -76,6 +93,7 @@ void webBegin() {
server.on("/", handleRoot);
server.on("/api/current", handleCurrent);
server.on("/api/history", handleHistory);
server.on("/api/forecasts", handleForecasts);
server.on("/api/settings", HTTP_GET, handleGetSettings);
server.on("/api/settings", HTTP_POST, handlePostSettings);
server.begin();