Initial version of weather microservice

This commit is contained in:
2023-05-07 11:51:01 +02:00
parent 27065dc73d
commit f1698db0e2
12 changed files with 197 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct WeatherResponse {
pub id: usize,
pub weather: Vec<Weather>,
pub wind: Wind,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Weather {
pub id: usize,
pub main: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Wind {
pub speed: f32,
}
fn construct_weather_data_url(
base_url: &str,
latitude: &str,
longitude: &str,
api_key: &str,
current_datetime: &DateTime<Utc>,
) -> String {
format!(
"{}?lat={}&lon={}&dt={}&appid={}",
base_url, latitude, longitude, current_datetime.timestamp(), api_key
)
}
pub async fn fetch_weather_data(
base_url: &str,
latitude: &str,
longitude: &str,
api_key: &str,
current_datetime: &DateTime<Utc>,
) -> Result<WeatherResponse, reqwest::Error> {
let url = construct_weather_data_url(base_url, latitude, longitude, api_key, current_datetime);
reqwest::get(url).await?.json().await
}
#[cfg(test)]
mod test {
use super::*;
use chrono::prelude::*;
#[test]
fn should_construct_url() {
let result = construct_weather_data_url(
"http://test",
"1.14",
"1.12",
"abc",
&Utc.with_ymd_and_hms(2023, 1, 2, 1, 0, 0).unwrap(),
);
assert_eq!("http://test?lat=1.14&lon=1.12&dt=1672621200&appid=abc", result);
}
}

View File

@@ -0,0 +1,15 @@
use serde::Deserialize;
use crate::mode::Mode;
#[derive(Deserialize, Debug)]
pub struct Input
{
#[serde(default)]
pub program_mode: Mode,
pub weather_api_base_url: String,
pub weather_api_key: String,
pub influx_db_base_url: String,
pub influx_db_token: String,
pub latitude: String,
pub longitude: String
}

View File

@@ -0,0 +1,47 @@
mod fetch;
mod input;
mod mode;
mod write;
use anyhow::Result;
use config::Config;
use log::info;
use chrono::Utc;
#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
let settings: input::Input = fetch_settings()?;
match settings.program_mode
{
mode::Mode::ReadWeatherData => read_weather_data(&settings).await?
};
Ok(())
}
async fn read_weather_data(settings: &input::Input) -> Result<()> {
info!("Start fetching weather data...");
let result = fetch::fetch_weather_data(&settings.weather_api_base_url, &settings.latitude, &settings.longitude, &settings.weather_api_key, &Utc::now()).await?;
info!("Start writing weather data...");
let map = write::WeatherReading {
wind_speed: result.wind.speed,
time: Utc::now(),
};
write::write_weather_data(map, &settings.influx_db_base_url, "homeassistant", &settings.influx_db_token).await?;
Ok(())
}
fn fetch_settings() -> Result<input::Input, config::ConfigError> {
let settings = Config::builder()
// Add in `./Settings.toml`
.add_source(config::File::with_name("./Settings").required(false))
.add_source(config::Environment::with_prefix("weather"))
.build()
.unwrap();
settings.try_deserialize::<input::Input>()
}

View File

@@ -0,0 +1,7 @@
use serde::Deserialize;
#[derive(Deserialize, Debug, Default)]
pub enum Mode {
#[default]
ReadWeatherData,
}

View File

View File

@@ -0,0 +1,21 @@
use chrono::{DateTime, Utc};
use influxdb::{Client, InfluxDbWriteable};
use anyhow::Result;
#[derive(InfluxDbWriteable)]
pub struct WeatherReading {
pub time: DateTime<Utc>,
pub wind_speed: f32,
}
pub async fn write_weather_data(
reading: WeatherReading,
base_url: &str,
database: &str,
token: &str,
) -> Result<()> {
let client = Client::new(base_url, database).with_token(token);
let query = reading.into_query("WeatherReading");
client.query(query).await?;
Ok(())
}