commit ea90ef364f5cca0ce56d90e659813d356fad138a Author: Vitali Date: Fri Jul 17 18:28:17 2026 +0700 docs: add Weather Predictor design spec Autonomous barometric weather station on Wemos D1 mini with BMP180, DS3231 RTC and 0.96" ST7735 TFT. Local Zambretti forecast, web UI, LittleFS storage, WiFiManager + NTP. Co-Authored-By: Claude Opus 4.8 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..546504d --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Arduino / build artifacts +build/ +*.bin +*.elf +*.hex +.vscode/ +# OS +Thumbs.db +Desktop.ini +.DS_Store +# Secrets (Wi-Fi creds are set via WiFiManager, not committed) +secrets.h diff --git a/docs/superpowers/specs/2026-07-17-weather-predictor-design.md b/docs/superpowers/specs/2026-07-17-weather-predictor-design.md new file mode 100644 index 0000000..1751bc8 --- /dev/null +++ b/docs/superpowers/specs/2026-07-17-weather-predictor-design.md @@ -0,0 +1,168 @@ +# Weather Predictor — Design Spec + +**Date:** 2026-07-17 +**Status:** Approved (design), pending implementation plan + +## Overview + +An autonomous barometric weather-prediction station built on a Wemos D1 mini +(ESP8266). It measures atmospheric pressure and temperature (BMP180), keeps +accurate time (DS3231 RTC), predicts near-term weather locally using the +**Zambretti algorithm** (pressure trend based, no internet required), and +displays current readings + forecast on a small TFT. A built-in web interface +(served from the device) shows live readings, a 24 h history chart, and +editable settings. + +All on-device and web text is in **English**. + +## Hardware + +| Component | Model | +|-----------|-------| +| MCU | Wemos D1 mini (ESP8266, ~4 MB flash) | +| Pressure/Temp sensor | BMP180 (GY-68), I2C addr 0x77 | +| RTC | DS3231 (HW-022, no EEPROM), I2C addr 0x68, battery-backed | +| Display | 0.96" 80×160 TFT, ST7735S, 4-wire SPI, driver `INITR_MINI160x80` | + +### Wiring + +Display uses hardware SPI; both I2C modules share one bus (D1/D6). + +| Signal | Wemos pin | GPIO | +|--------|-----------|------| +| TFT CS | D8 | 15 | +| TFT DC | D3 | 0 | +| TFT RES | D4 | 2 | +| TFT SDA (MOSI) | D7 | 13 | +| TFT SCL (SCK) | D5 | 14 | +| TFT BLK (backlight) | D2 | 4 | +| I2C SCL (BMP180 + DS3231) | D1 | 5 | +| I2C SDA (BMP180 + DS3231) | D6 | 12 | + +Power: all modules on 3.3 V / GND. I2C init: `Wire.begin(D6 /*SDA*/, D1 /*SCL*/)`. + +## Software Architecture + +Arduino IDE project: main `.ino` sketch + per-module `.h`/`.cpp` tabs. +Each module has one clear responsibility and a small interface. + +| Module | Responsibility | Key library | +|--------|----------------|-------------| +| `config.h` | Pins, I2C addresses, timing constants, defaults | — | +| `sensors` | Read BMP180 pressure + temperature | Adafruit_BMP085 | +| `rtc` | Read/set DS3231 time; NTP sync when Wi-Fi up | RTClib | +| `display` | Render the status screen | Adafruit_GFX, Adafruit_ST7735 | +| `forecast` | Zambretti prediction (pure, host-testable) | — | +| `history` | Ring buffer of samples + LittleFS persistence | LittleFS | +| `settings` | Load/save settings JSON | ArduinoJson, LittleFS | +| `wifi` | Connect via WiFiManager captive portal | WiFiManager | +| `webserver` | HTTP server + REST API + static page | ESP8266WebServer | + +### Third-party libraries (Arduino Library Manager) + +Adafruit_GFX, Adafruit_ST7735, Adafruit_BMP085 (works for BMP180), RTClib, +ArduinoJson, WiFiManager (tzapu). Built-in: SPI, Wire, ESP8266WiFi, +ESP8266WebServer, LittleFS, time.h (NTP/SNTP). + +## Forecast Logic (Zambretti) + +1. BMP180 reports **absolute** pressure → convert to **mean sea-level (MSL)** + pressure using the configured altitude (barometric formula). +2. Store MSL pressure samples in the history buffer. +3. Compute the **3-hour pressure trend** → rising / steady / falling + (threshold ≈ ±1.6 hPa over 3 h). +4. Zambretti lookup from (MSL pressure, trend, season-from-month) → one of + ~26 forecast codes → mapped to a short English label + (e.g. `Sunny`, `Fine`, `Changeable`, `Rain likely`, `Stormy`) + an icon + + trend arrow (↑ / → / ↓). +5. Until ~3 h of data exist after boot, show `Collecting data…`. + +Southern-hemisphere handling is not needed (fixed northern location); season +derived from RTC month. + +## Display Layout (80×160, portrait) + +Top→bottom: large time `HH:MM`; date; MSL pressure (hPa) with trend arrow; +temperature (°C); forecast label + icon. Backlight on D2 (dimming/night mode +is a possible later enhancement, not in initial scope). + +## Data Flow + +``` +BMP180 ──▶ sensors ──▶ MSL convert ──▶ history (RAM ring buffer) +DS3231 ──▶ rtc │ + ▼ + forecast (Zambretti) ──┬──▶ display + └──▶ webserver /api +history ──(every ~15 min)──▶ LittleFS (restored on boot) +settings ◀──▶ LittleFS (edited via web) +``` + +- Sensor sampling: every ~1 min (display/current values). +- History granularity: one stored sample every ~5 min → ~24–48 h in RAM. +- Flash flush: every ~15 min (and buffer capped) to limit flash wear. + +## Web Interface + +Single page served from the device; **no external CDNs** (works even if the +client has no internet). Vanilla JS + a small self-written inline **SVG chart**. + +Pages/sections: +1. **Live** — current time, MSL pressure + trend, temperature, forecast. +2. **History** — 24 h pressure + temperature chart. +3. **Settings** — altitude (m, default 150), timezone/UTC offset, default + coordinates (54.9870, 82.8730) shown; editable and persisted to LittleFS. + +REST API: +- `GET /api/current` → time, pressure (abs + MSL), temperature, trend, forecast. +- `GET /api/history` → array of recent samples for the chart. +- `GET /api/settings` / `POST /api/settings` → read/update settings. + +## Storage (LittleFS) + +- `/settings.json` — altitude, timezone offset, coordinates. +- `/history.dat` (or `.json`) — periodic snapshot of the sample ring buffer, + reloaded on boot so the trend survives restarts. + +## Wi-Fi & Time + +- **WiFiManager**: on first boot (or no known network) the device opens a + captive-portal AP so Wi-Fi is configured from a phone — no reflashing. +- **NTP**: when Wi-Fi is connected, sync time and write it to the DS3231. + DS3231 (battery-backed) keeps accurate time when offline. +- Default location for timezone context: 54.9870 N, 82.8730 E (Novosibirsk, + UTC+7), altitude 150 m — all editable via web. + +## Defaults Summary + +| Setting | Default | Editable in web | +|---------|---------|-----------------| +| Altitude | 150 m | yes | +| Coordinates | 54.9870, 82.8730 | yes | +| Timezone | UTC+7 | yes | +| Sensor sample interval | ~60 s | no (constant) | +| History sample interval | ~5 min | no (constant) | +| Flash flush interval | ~15 min | no (constant) | + +## Testing + +Manual (Arduino IDE, no automated harness): + +1. **Sensors** — Serial print of BMP180 pressure/temp; sanity-check values. +2. **RTC** — set time, power-cycle, verify time held by battery; verify NTP + sync updates DS3231. +3. **MSL conversion** — verify computed sea-level pressure is plausible for + 150 m (abs ≈ MSL − ~18 hPa). +4. **Trend/forecast** — inject synthetic pressure series via Serial or by + editing the buffer; confirm rising/steady/falling classification and + Zambretti label mapping against known reference values. +5. **Display** — verify layout, no overflow, correct icons/arrows. +6. **Web** — load page over LAN, confirm live values, chart renders, settings + save and persist across reboot. +7. **Persistence** — reboot; confirm settings and history restored from flash. + +## Out of Scope (initial) + +- Online forecast providers (variant B/C hybrid). +- Cyrillic display fonts (English only). +- Backlight night dimming, CSV/JSON export (possible later enhancements).