continue on the simplified view of weather

Signed-off-by: Christine Dodrill <me@christine.website>
This commit is contained in:
Cadey Ratio 2020-12-23 17:43:11 -05:00
parent 76611d657a
commit 02ef9809c7
3 changed files with 152 additions and 9 deletions

View File

@ -32,9 +32,10 @@ fn main() -> Result<()> {
let fin = DecodeReaderBytesBuilder::new()
.encoding(Some(WINDOWS_1252))
.build(resp.into_reader());
let data: web::canada_weather::SiteData = from_reader(fin)?;
let data: web::canada_weather::types::SiteData = from_reader(fin)?;
let data: web::canada_weather::Report = data.into();
println!("{:#?}", data);
println!("{}", serde_json::to_string_pretty(&data)?);
Ok(())
}

View File

@ -1,5 +1,7 @@
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
pub mod types;
pub use types::SiteData;
/// The credit string for this data.
///
@ -8,3 +10,122 @@ pub use types::SiteData;
/// This must be manually included in each response to remain within the scope
/// of the license.
pub const DATA_SOURCE: &'static str = "Data Source: Environment and Climate Change Canada";
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Report {
pub data_source: String,
pub location: Location,
pub conditions: Conditions,
pub forecast: Vec<Forecast>,
}
impl From<types::SiteData> for Report {
fn from(sd: types::SiteData) -> Self {
let forecast: Vec<Forecast> = sd
.forecast_group
.forecast
.into_iter()
.map(Into::into)
.collect();
Report {
data_source: DATA_SOURCE.to_string(),
location: sd.location.into(),
conditions: sd.current_conditions.into(),
forecast: forecast,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Location {
pub lat: String,
pub lon: String,
pub code: String,
pub name: String,
pub region: String,
}
impl From<types::Location> for Location {
fn from(l: types::Location) -> Self {
Location {
lat: l.name.lat.unwrap(),
lon: l.name.lon.unwrap(),
code: l.name.code,
name: l.name.name,
region: l.region,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Conditions {
pub as_of_utc: NaiveDateTime,
pub as_of_local: NaiveDateTime,
pub condition: String,
pub temperature: f64,
pub dewpoint: f64,
pub windchill: Option<f64>,
/// This is in kilo-Pascals
pub pressure: f64,
pub humidity: f64,
pub icon_url: String,
}
impl From<types::CurrentConditions> for Conditions {
fn from(cc: types::CurrentConditions) -> Self {
let dt: Vec<NaiveDateTime> = cc.date_time.clone().into_iter().map(Into::into).collect();
Conditions {
as_of_utc: dt[0],
as_of_local: dt[1],
condition: cc.condition,
temperature: cc.temperature.value.unwrap(),
dewpoint: cc.dewpoint.value.unwrap(),
windchill: match cc.wind_chill {
None => None,
Some(wc) => Some(wc.value.unwrap()),
},
pressure: cc.pressure.value.unwrap(),
humidity: cc.relative_humidity.value.unwrap(),
icon_url: format!(
"https://weather.gc.ca/weathericons/{}.{}",
cc.icon_code.value, cc.icon_code.format
),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Forecast {
pub period: String,
pub summary: String,
pub icon_url: String,
pub temp_summary: String,
pub high: Option<f64>,
pub low: Option<f64>,
pub humidity: f64,
}
impl From<types::Forecast> for Forecast {
fn from(f: types::Forecast) -> Self {
Self {
period: f.period.value,
summary: f.text_summary,
icon_url: format!(
"https://weather.gc.ca/weathericons/{}.{}",
f.abbreviated_forecast.icon_code.value, f.abbreviated_forecast.icon_code.format
),
temp_summary: f.temperatures.text_summary,
high: if f.temperatures.temperature.class.as_ref().unwrap() == "high" {
f.temperatures.temperature.value
} else {
None
},
low: if f.temperatures.temperature.class.as_ref().unwrap() == "low" {
f.temperatures.temperature.value
} else {
None
},
humidity: f.relative_humidity.value.unwrap(),
}
}
}

View File

@ -1,3 +1,4 @@
use chrono::{FixedOffset, NaiveDate, NaiveDateTime, TimeZone};
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
@ -19,7 +20,7 @@ pub struct SiteData {
pub struct Name {
pub name: String,
#[serde(rename = "$value")]
pub value: u8,
pub value: u32,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
@ -28,16 +29,35 @@ pub struct DateTime {
pub name: String,
pub zone: String,
#[serde(rename = "UTCOffset")]
pub utc_offset: String,
pub year: u16,
pub utc_offset: i32,
pub year: i32,
pub month: Name,
pub day: Name,
pub hour: u8,
pub minute: u8,
pub hour: u32,
pub minute: u32,
pub time_stamp: String,
pub text_summary: String,
}
impl Into<NaiveDateTime> for DateTime {
fn into(self) -> NaiveDateTime {
NaiveDate::from_ymd(self.year, self.month.value, self.day.value).and_hms(
self.hour,
self.minute,
0,
)
}
}
impl Into<chrono::DateTime<FixedOffset>> for DateTime {
fn into(self) -> chrono::DateTime<FixedOffset> {
let hour = 3600;
FixedOffset::east(self.utc_offset * hour)
.ymd(self.year, self.month.value, self.day.value)
.and_hms(self.hour, self.minute, 0)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Location {
@ -73,6 +93,7 @@ pub struct MetricWithUnits {
pub unit_type: Option<String>,
pub change: Option<f64>,
pub tendency: Option<String>,
pub class: Option<String>,
#[serde(rename = "$value")]
pub value: Option<f64>,
}
@ -152,7 +173,7 @@ pub struct CloudPrecip {
pub struct Forecast {
pub period: Period,
pub text_summary: String,
pub cloud_precip: CloudPrecip,
pub cloud_precip: Option<CloudPrecip>,
pub abbreviated_forecast: AbbreviatedForecast,
pub temperatures: Temperatures,
pub winds: Winds,