Skip to content

Commit 2026555

Browse files
committed
feat(radar): rain radar tab with FMI observed + forecast overlay
New "Sade" tab: a Leaflet map centred on the saved location with pinch-zoom/pan, an animated timeline, and a recenter button. Backend (radar module): - GET /api/radar/frames — last-hour observed radar frames from FMI WMS capabilities (5-min steps). - GET /api/radar/wms — transparent proxy for FMI WMS GetMap tiles. - GET /api/radar/forecast — FMI HARMONIE precip forecast: fetch the EPSG:4326 GRIB2 grid, decode with the `grib` crate (no native deps), read grid geometry from the GDS, orient north-up, block-max downsample, convert metres→mm, return a compact JSON grid. Retries transient FMI drops; cached. Frontend (RainMap, lazy-loaded): - Observed WMS frames + forecast heat overlays merged into one timeline with a "now" divider, play/pause, frame slider, long-press swipe scrub, relative-time labels, and a precipitation legend. FMI WMS/WFS need no API key; new FMI_WMS_BASE_URL / FMI_DOWNLOAD_BASE_URL settings default to the public endpoints.
1 parent b547509 commit 2026555

14 files changed

Lines changed: 1462 additions & 2 deletions

File tree

‎backend/Cargo.lock‎

Lines changed: 184 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎backend/Cargo.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ hmac = "0.13.0"
2929
sha1 = "0.11.0"
3030
md5 = "0.8.0"
3131
base64 = "0.22.1"
32+
grib = { version = "0.15.6", default-features = false }
3233

3334
[dev-dependencies]
3435
wiremock = "0.6"

‎backend/src/lib.rs‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod cache;
22
pub mod hue;
33
pub mod pv;
4+
pub mod radar;
45
pub mod reserve;
56
pub mod settings;
67
pub mod solis;
@@ -30,6 +31,8 @@ pub struct AppState {
3031
pub solis_cache: Cache<solis::models::SolisWidgetData>,
3132
pub pv_cache: Cache<pv::models::PvForecast>,
3233
pub spot_cache: Cache<spot::models::SpotResponse>,
34+
pub radar_frames_cache: Cache<radar::models::RadarFrames>,
35+
pub precip_forecast_cache: Cache<radar::models::PrecipForecast>,
3336
pub hue_events_tx: broadcast::Sender<hue::events::HueLiveEvent>,
3437
pub storage: storage::Storage,
3538
}
@@ -51,6 +54,8 @@ pub struct AppState {
5154
pv::handlers::post_forecast,
5255
reserve::handlers::get_reserve,
5356
spot::handlers::get_spot,
57+
radar::handlers::frames,
58+
radar::handlers::forecast,
5459
status,
5560
sensor_history,
5661
),
@@ -72,6 +77,9 @@ pub struct AppState {
7277
reserve::models::ReservePoint,
7378
spot::models::SpotResponse,
7479
spot::models::HourPrice,
80+
radar::models::RadarFrames,
81+
radar::models::PrecipForecast,
82+
radar::models::ForecastFrame,
7583
StatusResponse,
7684
storage::SensorReading,
7785
))
@@ -230,7 +238,13 @@ pub fn create_app(
230238
.service(
231239
web::scope("/reserve").route("", web::get().to(reserve::handlers::get_reserve)),
232240
)
233-
.service(web::scope("/spot").route("", web::get().to(spot::handlers::get_spot))),
241+
.service(web::scope("/spot").route("", web::get().to(spot::handlers::get_spot)))
242+
.service(
243+
web::scope("/radar")
244+
.route("/frames", web::get().to(radar::handlers::frames))
245+
.route("/forecast", web::get().to(radar::handlers::forecast))
246+
.route("/wms", web::get().to(radar::handlers::wms)),
247+
),
234248
)
235249
.service(SwaggerUi::new("/docs/{_:.*}").url("/api-doc/openapi.json", openapi))
236250
.service({
@@ -275,6 +289,8 @@ pub fn create_test_app_state_with(settings: Settings) -> Arc<AppState> {
275289
solis_cache: Cache::new(std::time::Duration::from_secs(300)),
276290
pv_cache: Cache::new(std::time::Duration::from_secs(60)),
277291
spot_cache: Cache::new(std::time::Duration::from_secs(600)),
292+
radar_frames_cache: Cache::new(std::time::Duration::from_secs(60)),
293+
precip_forecast_cache: Cache::new(std::time::Duration::from_secs(1800)),
278294
hue_events_tx,
279295
storage,
280296
})
@@ -315,6 +331,8 @@ pub async fn run_server() -> std::io::Result<()> {
315331
solis_cache: Cache::new(std::time::Duration::from_secs(300)),
316332
pv_cache: Cache::new(std::time::Duration::from_secs(60)),
317333
spot_cache: Cache::new(std::time::Duration::from_secs(600)),
334+
radar_frames_cache: Cache::new(std::time::Duration::from_secs(60)),
335+
precip_forecast_cache: Cache::new(std::time::Duration::from_secs(1800)),
318336
hue_events_tx: hue_events_tx.clone(),
319337
storage,
320338
});

0 commit comments

Comments
 (0)