azalea_shell/service/
weather.rs

1use tokio::sync::broadcast;
2
3#[derive(azalea_derive::StaticServiceManager)]
4pub struct Service {
5    client: open_meteo_rs::Client,
6}
7
8#[derive(Clone, Default)]
9pub struct Init {}
10
11#[derive(Clone, Debug)]
12pub enum Input {
13    Update,
14}
15
16#[derive(Clone, Debug)]
17pub enum Output {
18    Temperature((f64, String)),
19}
20
21impl azalea_service::Service for Service {
22    type Init = Init;
23    type Input = Input;
24    type Event = ();
25    type Output = Output;
26
27    const DISABLE_EVENTS: bool = true;
28
29    async fn new(
30        _init: Self::Init,
31        sender: flume::Sender<Self::Input>,
32        _output_sender: broadcast::Sender<Self::Output>,
33    ) -> Self {
34        let client = open_meteo_rs::Client::new();
35
36        drop(sender.send(Input::Update));
37
38        Self { client }
39    }
40
41    async fn message(
42        &mut self,
43        input: Self::Input,
44        output_sender: &broadcast::Sender<Self::Output>,
45    ) {
46        match input {
47            Input::Update => {
48                if let Some(temperature) = self.get_temperature().await {
49                    drop(output_sender.send(Output::Temperature(temperature)));
50                }
51            }
52        }
53    }
54}
55
56impl Service {
57    async fn get_temperature(&self) -> Option<(f64, String)> {
58        let mut opts = open_meteo_rs::forecast::Options::default();
59
60        opts.location = open_meteo_rs::Location {
61            lat: -23.5558,
62            lng: -46.6396,
63        };
64
65        opts.temperature_unit = Some(open_meteo_rs::forecast::TemperatureUnit::Celsius); // or
66        opts.wind_speed_unit = Some(open_meteo_rs::forecast::WindSpeedUnit::Kmh); // or
67        opts.precipitation_unit = Some(open_meteo_rs::forecast::PrecipitationUnit::Millimeters); // or
68        opts.current.push("temperature_2m".into());
69
70        let res = self.client.forecast(opts).await.unwrap();
71        res.current.and_then(|res| {
72            if let Some(temp) = res.values.get("temperature_2m") {
73                Some((
74                    match temp.value.clone() {
75                        serde_json::Value::Number(number) => number.as_f64().unwrap_or(0.),
76                        _ => 0.,
77                    },
78                    temp.unit.clone().unwrap_or(format!("C°")),
79                ))
80            } else {
81                None
82            }
83        })
84    }
85}