Add the Luchtmeetnet provider
Also introduce the providers module.
This commit is contained in:
parent
cbd686bd60
commit
59c177d508
4 changed files with 73 additions and 2 deletions
|
@ -8,5 +8,5 @@ chrono = "0.4.19"
|
|||
color-eyre = "0.5.6"
|
||||
geocoding = "0.3.1"
|
||||
image = "0.24.0"
|
||||
reqwest = "0.11.9"
|
||||
reqwest = { version = "0.11.9", features = ["json"] }
|
||||
rocket = { version = "0.5.0-rc.1", features = ["json"] }
|
||||
|
|
|
@ -21,8 +21,10 @@ use rocket::tokio::{self, select};
|
|||
use rocket::{get, routes, FromFormField, State};
|
||||
|
||||
use self::maps::{Maps, MapsHandle};
|
||||
use self::providers::luchtmeetnet::Item as LuchtmeetnetItem;
|
||||
|
||||
mod maps;
|
||||
pub(crate) mod maps;
|
||||
pub(crate) mod providers;
|
||||
|
||||
/// The current for a specific location.
|
||||
///
|
||||
|
|
5
src/providers.rs
Normal file
5
src/providers.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
//! All supported metric data providers.
|
||||
//!
|
||||
//! Data is either provided via a direct (JSON) API or via looking up values on maps.
|
||||
|
||||
pub(crate) mod luchtmeetnet;
|
64
src/providers/luchtmeetnet.rs
Normal file
64
src/providers/luchtmeetnet.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
//! The Luchtmeetnet open data provider.
|
||||
//!
|
||||
//! For more information about Luchtmeetnet, see: <https://www.luchtmeetnet.nl/contact>.
|
||||
|
||||
use chrono::serde::ts_seconds;
|
||||
use chrono::{DateTime, Utc};
|
||||
use rocket::serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::Metric;
|
||||
|
||||
/// The base URL for the Luchtmeetnet API.
|
||||
const LUCHTMEETNET_BASE_URL: &str = "https://api.luchtmeetnet.nl/open_api/concentrations";
|
||||
|
||||
/// The Luchtmeetnet API data container.
|
||||
///
|
||||
/// This is only used temporarily during deserialization.
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
struct Container {
|
||||
data: Vec<Item>,
|
||||
}
|
||||
|
||||
/// The Luchtmeetnet API data item.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub(crate) struct Item {
|
||||
/// The time for when the value is forecast.
|
||||
#[serde(
|
||||
rename(deserialize = "timestamp_measured"),
|
||||
serialize_with = "ts_seconds::serialize"
|
||||
)]
|
||||
time: DateTime<Utc>,
|
||||
/// The forecasted value.
|
||||
///
|
||||
/// The unit depends on the selected [metric](Metric).
|
||||
value: f32,
|
||||
}
|
||||
|
||||
/// Retrieves the Luchtmeetnet forecasted items for the provided position and metric.
|
||||
///
|
||||
/// Returns [`None`] if retrieval or deserialization fails, or if the metric is not supported by
|
||||
/// this provider.
|
||||
pub(crate) async fn get(lat: f64, lon: f64, metric: Metric) -> Option<Vec<Item>> {
|
||||
let formula = match metric {
|
||||
Metric::AQI => "lki",
|
||||
Metric::NO2 => "no2",
|
||||
Metric::O3 => "o3",
|
||||
Metric::PM10 => "pm10",
|
||||
_ => return None, // Unsupported metric
|
||||
};
|
||||
let url = format!(
|
||||
"{LUCHTMEETNET_BASE_URL}?formula={formula}&latitude={:.05}&longitude={:.05}",
|
||||
lat, lon
|
||||
);
|
||||
|
||||
println!("▶️ Retrieving Luchtmeetnet data from {url}");
|
||||
let response = reqwest::get(&url).await.ok()?;
|
||||
let root: Container = match response.error_for_status() {
|
||||
Ok(res) => res.json().await.ok()?,
|
||||
Err(_err) => return None,
|
||||
};
|
||||
|
||||
Some(root.data)
|
||||
}
|
Loading…
Reference in a new issue