feat: integrate scheduler and full status display (landscape 160x80)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 20:18:36 +07:00
co-authored by Claude Opus 4.8
parent 4e53e7388f
commit 0a8dbe198d
4 changed files with 142 additions and 59 deletions
+44 -53
View File
@@ -1,80 +1,71 @@
#include <Arduino.h>
#include <Wire.h>
#include "config.h"
#include "display_ui.h"
#include "sensors.h"
#include "rtc_time.h"
#include "display_ui.h"
#include "forecast.h"
#include "history.h"
#include "app_settings.h"
#include "state.h"
static void i2cScan() {
Serial.println(F("I2C scan:"));
byte found = 0;
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.printf(" device at 0x%02X\n", addr);
found++;
}
AppState g_state;
static unsigned long tSample = 0;
static unsigned long tHistory = 0;
static void sampleNow() {
g_state.now = rtcNow();
g_state.absHpa = readAbsPressureHpa();
g_state.mslHpa = toSeaLevelHpa(g_state.absHpa, settings.altitudeM);
g_state.tempC = readTemperatureC();
float d;
g_state.haveTrend = historyTrendDelta(d);
if (g_state.haveTrend) {
g_state.trend = classifyTrend(d);
g_state.forecast = computeForecast(g_state.mslHpa, g_state.trend, g_state.now.month);
} else {
g_state.trend = TREND_STEADY;
}
Serial.printf(" %d device(s) found\n", found);
}
void setup() {
Serial.begin(115200);
delay(200);
Serial.println(F("\n=== Weather Predictor booting ==="));
Wire.begin(I2C_SDA, I2C_SCL); // MUST come before any I2C driver begin()
i2cScan();
Serial.println(F("\n=== Weather Predictor ==="));
Wire.begin(I2C_SDA, I2C_SCL);
displayBegin();
displaySplash("Weather", "Predictor v0.1");
displaySplash("Weather", "Predictor");
if (!sensorsBegin()) Serial.println(F("BMP180 not found!"));
if (!rtcBegin()) Serial.println(F("DS3231 not found!"));
if (rtcLostPower()) {
Serial.println(F("RTC lost power -> setting to build time"));
rtcSet(RtcTime{2026, 7, 17, 12, 0, 0}); // temporary; NTP will correct later
Serial.println(F("RTC lost power -> temporary time set"));
rtcSet(RtcTime{2026, 7, 17, 12, 0, 0});
}
// --- forecast self-test (remove after Task 8) ---
struct { float p; Trend tr; } cases[] = {
{1030, TREND_STEADY}, {1030, TREND_RISING}, {1030, TREND_FALLING},
{1000, TREND_STEADY}, {1000, TREND_FALLING}, {970, TREND_FALLING},
};
for (auto& c : cases) {
Forecast f = computeForecast(c.p, c.tr, 7);
Serial.printf("p=%.0f trend=%d -> %c [%s] (%s)\n",
c.p, c.tr, f.letter, f.text, categoryShort(f.category));
}
// --- history self-test (remove after Task 8) ---
historyBegin();
uint32_t base = 1000000000UL;
for (int i = 0; i < 40; i++) // 40 samples @ 5 min = 3h20m, pressure falling
historyAdd(base + (uint32_t)i * 300, 1015.0f - i * 0.2f, 20.0f);
float d;
if (historyTrendDelta(d))
Serial.printf("history count=%d 3h delta=%.2f hPa trend=%d\n",
historyCount(), d, classifyTrend(d));
else
Serial.println(F("history: not enough data for trend"));
// --- settings self-test (remove after Task 8) ---
settingsBegin();
Serial.printf("settings: alt=%.0f tz=%d lat=%.4f lon=%.4f\n",
settings.altitudeM, settings.tzOffsetMin, settings.lat, settings.lon);
settings.altitudeM += 1.0f; // change and persist to test round-trip
settingsSave();
Serial.println(F("settings: incremented altitude and saved"));
historyBegin();
// Seed first sample immediately.
sampleNow();
historyAdd(rtcEpoch(), g_state.mslHpa, g_state.tempC);
displayRender(g_state);
tSample = tHistory = millis();
}
void loop() {
RtcTime t = rtcNow();
float abs_ = readAbsPressureHpa();
Serial.printf("%04u-%02u-%02u %02u:%02u:%02u abs=%.1f msl=%.1f t=%.1f\n",
t.year, t.month, t.day, t.hour, t.minute, t.second,
abs_, toSeaLevelHpa(abs_, DEFAULT_ALTITUDE_M), readTemperatureC());
delay(2000);
unsigned long now = millis();
if (now - tSample >= SAMPLE_INTERVAL_MS) {
tSample = now;
sampleNow();
displayRender(g_state);
}
if (now - tHistory >= HISTORY_INTERVAL_MS) {
tHistory = now;
historyAdd(rtcEpoch(), g_state.mslHpa, g_state.tempC);
}
}