From 396688cd983bffa1a0a547af074b0521352fc2d7 Mon Sep 17 00:00:00 2001 From: Vitali Date: Fri, 17 Jul 2026 21:15:16 +0700 Subject: [PATCH] feat: HTTP server with REST API for current/history/settings Co-Authored-By: Claude Opus 4.8 --- WeatherPredictor/WeatherPredictor.ino | 6 ++ WeatherPredictor/web_page.h | 3 + WeatherPredictor/web_server.cpp | 84 +++++++++++++++++++++++++++ WeatherPredictor/web_server.h | 3 + 4 files changed, 96 insertions(+) create mode 100644 WeatherPredictor/web_page.h create mode 100644 WeatherPredictor/web_server.cpp create mode 100644 WeatherPredictor/web_server.h diff --git a/WeatherPredictor/WeatherPredictor.ino b/WeatherPredictor/WeatherPredictor.ino index 27532bb..b41dfa9 100644 --- a/WeatherPredictor/WeatherPredictor.ino +++ b/WeatherPredictor/WeatherPredictor.ino @@ -8,6 +8,7 @@ #include "history.h" #include "app_settings.h" #include "net.h" +#include "web_server.h" #include "state.h" AppState g_state; @@ -67,10 +68,15 @@ void setup() { sampleNow(); historyAdd(rtcEpoch(), g_state.mslHpa, g_state.tempC); displayRender(g_state); + + webBegin(); + if (netConnected()) Serial.printf("Web UI: http://%s/\n", netIP().c_str()); + tSample = tHistory = tFlush = millis(); } void loop() { + webLoop(); unsigned long now = millis(); if (now - tSample >= SAMPLE_INTERVAL_MS) { diff --git a/WeatherPredictor/web_page.h b/WeatherPredictor/web_page.h new file mode 100644 index 0000000..df1be1a --- /dev/null +++ b/WeatherPredictor/web_page.h @@ -0,0 +1,3 @@ +#pragma once +#include +static const char INDEX_HTML[] PROGMEM = "Weather Predictor

Weather Predictor

See /api/current

"; diff --git a/WeatherPredictor/web_server.cpp b/WeatherPredictor/web_server.cpp new file mode 100644 index 0000000..cfcfe16 --- /dev/null +++ b/WeatherPredictor/web_server.cpp @@ -0,0 +1,84 @@ +#include +#include +#include "state.h" +#include "app_settings.h" +#include "history.h" +#include "forecast.h" +#include "web_page.h" + +static ESP8266WebServer server(80); + +static void handleRoot() { + server.send_P(200, "text/html", INDEX_HTML); +} + +static void handleCurrent() { + JsonDocument doc; + char t[24]; + snprintf(t, sizeof(t), "%04u-%02u-%02u %02u:%02u:%02u", + g_state.now.year, g_state.now.month, g_state.now.day, + g_state.now.hour, g_state.now.minute, g_state.now.second); + doc["time"] = t; + doc["abs"] = g_state.absHpa; + doc["msl"] = g_state.mslHpa; + doc["temp"] = g_state.tempC; + doc["trend"] = (int)g_state.trend; + doc["haveTrend"] = g_state.haveTrend; + doc["forecast"] = g_state.haveTrend ? g_state.forecast.text : "Collecting data..."; + doc["category"] = g_state.haveTrend ? categoryShort(g_state.forecast.category) : "..."; + String out; + serializeJson(doc, out); + server.send(200, "application/json", out); +} + +static void handleHistory() { + JsonDocument doc; + JsonArray arr = doc.to(); + int n = historyCount(); + for (int i = 0; i < n; i++) { + Sample s = historyGet(i); + JsonObject o = arr.add(); + o["t"] = s.epoch; + o["msl"] = s.mslHpa; + o["temp"] = s.tempC; + } + String out; + serializeJson(doc, out); + server.send(200, "application/json", out); +} + +static void handleGetSettings() { + JsonDocument doc; + doc["altitude"] = settings.altitudeM; + doc["tz"] = settings.tzOffsetMin; + doc["lat"] = settings.lat; + doc["lon"] = settings.lon; + String out; + serializeJson(doc, out); + server.send(200, "application/json", out); +} + +static void handlePostSettings() { + JsonDocument doc; + if (deserializeJson(doc, server.arg("plain"))) { + server.send(400, "application/json", "{\"ok\":false,\"err\":\"bad json\"}"); + return; + } + settings.altitudeM = doc["altitude"] | settings.altitudeM; + settings.tzOffsetMin = doc["tz"] | settings.tzOffsetMin; + settings.lat = doc["lat"] | settings.lat; + settings.lon = doc["lon"] | settings.lon; + settingsSave(); + server.send(200, "application/json", "{\"ok\":true}"); +} + +void webBegin() { + server.on("/", handleRoot); + server.on("/api/current", handleCurrent); + server.on("/api/history", handleHistory); + server.on("/api/settings", HTTP_GET, handleGetSettings); + server.on("/api/settings", HTTP_POST, handlePostSettings); + server.begin(); +} + +void webLoop() { server.handleClient(); } diff --git a/WeatherPredictor/web_server.h b/WeatherPredictor/web_server.h new file mode 100644 index 0000000..3ea8107 --- /dev/null +++ b/WeatherPredictor/web_server.h @@ -0,0 +1,3 @@ +#pragma once +void webBegin(); +void webLoop();