diff --git a/src/dwd.rs b/src/dwd.rs index 300e531..46f6f80 100644 --- a/src/dwd.rs +++ b/src/dwd.rs @@ -3,14 +3,14 @@ use std::collections::{BTreeMap, HashMap}; use reqwest::Url; use serde::Deserialize; -use crate::data::Data; - #[derive(Default)] pub struct DwdCache {} pub type Forecast = HashMap; #[derive(Deserialize)] pub struct ForecastDatas { + #[serde(default)] + pub days: Vec, forecast0: Option, forecast1: Option, forecast2: Option, @@ -22,6 +22,21 @@ pub struct ForecastDatas { forecast8: Option, forecast9: Option, } +#[derive(Deserialize)] +pub struct ForecastDay { + #[serde(rename = "dayDate")] + pub date: String, + // #[serde(rename = "moonPhase")] + // pub moon_phase: Option, + // #[serde(rename = "moonriseOnThisDay")] + pub moonrise: Option, + // #[serde(rename = "moonsetOnThisDay")] + pub moonset: Option, + // #[serde(rename = "sunriseOnThisDay")] + pub sunrise: Option, + // #[serde(rename = "sunsetOnThisDay")] + pub sunset: Option, +} impl ForecastDatas { pub fn forecasts(&self) -> impl Iterator { [ diff --git a/src/main.rs b/src/main.rs index e0a3617..19be687 100644 --- a/src/main.rs +++ b/src/main.rs @@ -247,6 +247,22 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page { i += 1; i }; + let additional = |date| { + forecast + .values() + .flat_map(|forecast| forecast.days.iter()) + .find(|day| day.date == date) + .map(|day| { + ( + day.sunrise + .and_then(|rise| day.sunset.map(|set| (rise, set))) + .map(|(rise, set)| (rise / 1000.0, set / 1000.0)), + day.moonrise + .and_then(|rise| day.moonset.map(|set| (rise, set))) + .map(|(rise, set)| (rise / 1000.0, set / 1000.0)), + ) + }) + }; diagram_head(&mut body); diagram( ("Temperature", "°C", 5.0), @@ -261,6 +277,7 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page { avg(forecasts(&forecast) .flat_map(move |forecast| forecast.temperature(time))) }, + additional, timer.clone(), &mut body, ); @@ -272,6 +289,7 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page { avg(forecasts(&forecast) .flat_map(move |forecast| forecast.precipitation(time))) }, + additional, timer.clone(), &mut body, ); @@ -283,6 +301,7 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page { avg(forecasts(&forecast) .flat_map(move |forecast| forecast.sunshine(time))) }, + additional, timer.clone(), &mut body, ); @@ -294,6 +313,7 @@ async fn weather_overview(q: &str, data: &State, accept: &Accept) -> Page { avg(forecasts(&forecast) .flat_map(move |forecast| forecast.humidity(time))) }, + additional, timer.clone(), &mut body, ); @@ -329,7 +349,7 @@ a { overflow-x: scroll; } .diagram { - height: 10em; + height: 12em; margin: 0px; border: 0px; padding: 0px; @@ -347,6 +367,7 @@ fn diagram( (dindex, fmin, fmax): (usize, Option, Option), gradient: &[(f64, &str)], f: impl Fn(f64) -> Option, + additional: impl Fn(String) -> Option<(Option<(f64, f64)>, Option<(f64, f64)>)>, mut timer: TimeStepper, body: &mut String, ) { @@ -394,7 +415,7 @@ fn diagram( let scale_value = |v: f64| (max - v) * 1000.0 / (max - min); let scaled_end = scale_time(end); *body += &format!( - r##""##, + r##""##, scaled_end + 500.0, ); let shape_head = format!(r##" f64 { + date.and_time(NaiveTime::from_hms_opt(0, 0, 0).unwrap()) + .and_local_timezone(Local) + .earliest() + .unwrap() + .signed_duration_since(DateTime::UNIX_EPOCH) + .as_seconds_f64() + } + let day_start = unix_day_start(date); + let (date, day_end) = if let Some(succ) = date.succ_opt() { + (std::mem::replace(&mut date, succ), unix_day_start(succ)) } else { break; - } + }; if day_start > end { break; } else if day_start < start { continue; } + if let Some((sun, moon)) = additional(date.to_string()) { + for (risenset, color1, color2, y) in + [(sun, "#FF08", "#FB08", 150), (moon, "#88F8", "#00F6", 130)] + { + if let Some((rise, set)) = risenset { + for (t, color) in [(rise, color1), (set, color2)] { + let x = scale_time(t); + *body += &format!( + r#""#, + ); + } + } + } + } + for (i, x) in (0..) + .map(|i| (i, day_end + (i as f64 - 24.0) * 3600.0)) + .skip_while(|(_, t)| *t <= day_start) + .take_while(|(_, t)| *t < day_end && *t <= end) + .map(|(i, t)| (i, scale_time(t))) + { + *body += &format!( + r##""##, + match i { + 6 | 12 | 18 => "50", + _ => "80", + } + ); + } let x = scale_time(day_start); *body += &format!(r#""#); let x = scale_time(day_start + 3.0 * 3600.0);