use std::sync::Arc; use anyhow::{Error, Result}; use tibber::{Consumption, HomeId, House, PriceInfo, TibberSession, TimeResolution, User}; pub struct TibberHandler { session: Arc, pub user: User, pub homes: Vec<(HomeId, House)>, } impl TibberHandler { pub async fn new(token: impl ToString + Send + 'static) -> Result { tokio::task::spawn_blocking(move || { let session = Arc::new(TibberSession::new(token.to_string())); let user = session.get_user().map_err(|err| { Error::msg(format!( "TibberHandler: failed getting user information: {err:?}" )) })?; let mut homes = Vec::new(); for home_id in user.homes.clone().into_iter() { let house = session.get_home(&home_id).map_err(|err| { Error::msg(format!( "TibberHandler: failed getting house information: {err:?}" )) })?; homes.push((home_id, house)); } Ok(Self { homes, user, session, }) }) .await? } async fn get_data(&self, f: F) -> Result> where F: Fn(&TibberSession, &HomeId) -> Result + Send + Sync + Copy + 'static, T: Send + Sync + 'static, { let mut v = Vec::new(); for (home_id, house) in self.homes.iter() { v.push(( house.clone(), tokio::task::spawn_blocking({ let session = self.session.clone(); let home_id = home_id.clone(); move || f(&session, &home_id) }) .await??, )); } Ok(v) } pub async fn current_prices(&self) -> Result> { self.get_data(|session, home_id| { session.get_current_price(home_id).map_err(|err| { Error::msg(format!( "TibberHandler: failed getting current price: {err:?}" )) }) }) .await } pub async fn prices_today(&self) -> Result)>> { self.get_data(|session, home_id| { session.get_prices_today(home_id).map_err(|err| { Error::msg(format!( "TibberHandler: failed getting prices of today: {err:?}" )) }) }) .await } pub async fn prices_tomorrow(&self) -> Result)>> { self.get_data(|session, home_id| { session.get_prices_tomorrow(home_id).map_err(|err| { Error::msg(format!( "TibberHandler: failed getting prices for tomorrow: {err:?}" )) }) }) .await } pub async fn consumption( &self, resolution: TimeResolution, last: u32, ) -> Result)>> { let mut v = Vec::new(); for (home_id, house) in self.homes.iter() { v.push(( house.clone(), tokio::task::spawn_blocking({ let session = self.session.clone(); let home_id = home_id.clone(); let resolution = resolution.clone(); move || { session .get_consuption(&home_id, resolution, last) .map_err(|err| { Error::msg(format!( "TibberHandler: failed getting consumption: {err:?}" )) }) } }) .await??, )); } Ok(v) } } #[cfg(test)] mod test { use super::TibberHandler; use anyhow::Result; use std::fs; #[tokio::test] async fn test_connection() -> Result<()> { let tibber = TibberHandler::new(fs::read_to_string("tibber_token.txt")?).await?; let current_prices = tibber.current_prices().await?; println!("{current_prices:?}"); Ok(()) } }