Compare commits
2 commits
35836f9ec8
...
85ed9c1983
Author | SHA1 | Date | |
---|---|---|---|
85ed9c1983 | |||
6783b914d5 |
4 changed files with 191 additions and 2 deletions
|
@ -13,6 +13,7 @@ serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
tokio = { version = "1.33.0", features=["macros", "rt-multi-thread"] }
|
tokio = { version = "1.33.0", features=["macros", "rt-multi-thread"] }
|
||||||
|
tibber = "0.5.0"
|
||||||
chrono = "0.4.31"
|
chrono = "0.4.31"
|
||||||
actix-web = "4.4.0"
|
actix-web = "4.4.0"
|
||||||
actix-files = "0.6.2"
|
actix-files = "0.6.2"
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
fs,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
thread,
|
thread,
|
||||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||||
|
@ -11,8 +12,11 @@ mod db;
|
||||||
mod devices;
|
mod devices;
|
||||||
mod midea_helper;
|
mod midea_helper;
|
||||||
mod tasmota;
|
mod tasmota;
|
||||||
|
mod tibber_handler;
|
||||||
mod web_server;
|
mod web_server;
|
||||||
|
|
||||||
|
use tibber::TimeResolution::Daily;
|
||||||
|
|
||||||
use actix_files::Files;
|
use actix_files::Files;
|
||||||
use actix_web::{web::Data, App, HttpServer};
|
use actix_web::{web::Data, App, HttpServer};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
@ -20,6 +24,7 @@ use devices::Devices;
|
||||||
use futures::{future::try_join_all, try_join, Future};
|
use futures::{future::try_join_all, try_join, Future};
|
||||||
use midea_helper::MideaDishwasher;
|
use midea_helper::MideaDishwasher;
|
||||||
use tasmota::Tasmota;
|
use tasmota::Tasmota;
|
||||||
|
use tibber_handler::TibberHandler;
|
||||||
use web_server::*;
|
use web_server::*;
|
||||||
|
|
||||||
fn since_epoch() -> Result<u64> {
|
fn since_epoch() -> Result<u64> {
|
||||||
|
@ -88,8 +93,18 @@ async fn run_web_server(
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let db_future = DataBase::new("home_server.db");
|
let db_future = DataBase::new("home_server.db");
|
||||||
let devices_future = Devices::read("devices.conf");
|
let devices_future = Devices::read("devices.conf");
|
||||||
|
let tibber_future = TibberHandler::new(fs::read_to_string("tibber_token.txt")?);
|
||||||
|
|
||||||
let (db, devices, midea) = try_join!(db_future, devices_future, MideaDiscovery::discover())?;
|
let (db, devices, tibber, midea) = try_join!(
|
||||||
|
db_future,
|
||||||
|
devices_future,
|
||||||
|
tibber_future,
|
||||||
|
MideaDiscovery::discover()
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let prices_today = tibber.prices_today().await?;
|
||||||
|
let prices_tomorrow = tibber.prices_tomorrow().await?;
|
||||||
|
let consumption = tibber.consumption(Daily, 1).await?;
|
||||||
|
|
||||||
db.register_devices(&devices)?;
|
db.register_devices(&devices)?;
|
||||||
let shared_db = Arc::new(Mutex::new(db));
|
let shared_db = Arc::new(Mutex::new(db));
|
||||||
|
|
172
src/tibber.rs
Normal file
172
src/tibber.rs
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use anyhow::{Error, Result};
|
||||||
|
use tibber::{Consumption, HomeId, House, PriceInfo, TibberSession, TimeResolution, User};
|
||||||
|
|
||||||
|
pub struct TibberHandler {
|
||||||
|
session: Arc<TibberSession>,
|
||||||
|
pub user: User,
|
||||||
|
pub homes: Vec<(HomeId, House)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TibberHandler {
|
||||||
|
pub async fn new(token: impl ToString + Send + 'static) -> Result<Self> {
|
||||||
|
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<F, T>(&self, f: F) -> Result<Vec<(House, T)>>
|
||||||
|
where
|
||||||
|
F: Fn(&TibberSession, &HomeId) -> Result<T> + 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<Vec<(House, PriceInfo)>> {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
|
||||||
|
for (home_id, house) in self.homes.iter() {
|
||||||
|
v.push((
|
||||||
|
house.clone(),
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
self.session.get_current_price(home_id).map_err(|err| {
|
||||||
|
Error::msg(format!(
|
||||||
|
"TibberHandler: failed getting current price: {err:?}"
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn prices_today(&self) -> Result<Vec<(House, Vec<PriceInfo>)>> {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
|
||||||
|
for (home_id, house) in self.homes.iter() {
|
||||||
|
v.push((
|
||||||
|
house.clone(),
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
self.session.get_prices_today(home_id).map_err(|err| {
|
||||||
|
Error::msg(format!(
|
||||||
|
"TibberHandler: failed getting prices of today: {err:?}"
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn prices_tomorrow(&self) -> Result<Vec<(House, Vec<PriceInfo>)>> {
|
||||||
|
let mut v = Vec::new();
|
||||||
|
|
||||||
|
for (home_id, house) in self.homes.iter() {
|
||||||
|
v.push((
|
||||||
|
house.clone(),
|
||||||
|
tokio::task::spawn_blocking(move || {
|
||||||
|
self.session.get_prices_tomorrow(home_id).map_err(|err| {
|
||||||
|
Error::msg(format!(
|
||||||
|
"TibberHandler: failed getting prices for tomorrow: {err:?}"
|
||||||
|
))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.await?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn consumption(
|
||||||
|
&self,
|
||||||
|
resolution: TimeResolution,
|
||||||
|
last: u32,
|
||||||
|
) -> Result<Vec<(House, Vec<Consumption>)>> {
|
||||||
|
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 || {
|
||||||
|
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<()> {
|
||||||
|
TibberHandler::new(fs::read_to_string("tibber_token.txt")?).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
1
tibber_token.txt
Normal file
1
tibber_token.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
dkvF6ax77CP4v9-sxYyjWUD-9NunpzVPRYHfLJ8a9ps
|
Loading…
Reference in a new issue