Add tibber
This commit is contained in:
parent
abe8b2a91e
commit
6783b914d5
5 changed files with 211 additions and 2 deletions
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug executable 'home_server'",
|
||||
"cargo": {
|
||||
"args": [
|
||||
"build",
|
||||
"--bin=home_server",
|
||||
"--package=home_server"
|
||||
],
|
||||
"filter": {
|
||||
"name": "home_server",
|
||||
"kind": "bin"
|
||||
}
|
||||
},
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -12,4 +12,5 @@ reqwest = "0.11.20"
|
|||
serde = { version="1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
futures = "0.3.28"
|
||||
tokio = { version="1.32.0", features=["macros", "rt-multi-thread"] }
|
||||
tokio = { version="1.32.0", features=["macros", "rt-multi-thread"] }
|
||||
tibber = "0.5.0"
|
11
src/main.rs
11
src/main.rs
|
@ -1,4 +1,5 @@
|
|||
use std::{
|
||||
fs,
|
||||
sync::{Arc, Mutex},
|
||||
thread,
|
||||
time::{Duration, SystemTime, UNIX_EPOCH},
|
||||
|
@ -9,11 +10,14 @@ use crate::db::DataBase;
|
|||
mod db;
|
||||
mod devices;
|
||||
mod tasmota;
|
||||
mod tibber;
|
||||
|
||||
use ::tibber::TimeResolution::Daily;
|
||||
use anyhow::Result;
|
||||
use devices::Devices;
|
||||
use futures::{future::try_join_all, try_join};
|
||||
use tasmota::Tasmota;
|
||||
use tibber::TibberHandler;
|
||||
|
||||
fn since_epoch() -> Result<u64> {
|
||||
Ok(SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs())
|
||||
|
@ -23,8 +27,13 @@ fn since_epoch() -> Result<u64> {
|
|||
async fn main() -> Result<()> {
|
||||
let db_future = DataBase::new("home_server.db");
|
||||
let devices_future = Devices::read("devices.conf");
|
||||
let tibber_future = TibberHandler::new(fs::read_to_string("tibber_token.txt")?);
|
||||
|
||||
let (db, devices) = try_join!(db_future, devices_future)?;
|
||||
let (db, devices, tibber) = try_join!(db_future, devices_future, tibber_future)?;
|
||||
|
||||
let prices_today = tibber.prices_today().await?;
|
||||
let prices_tomorrow = tibber.prices_tomorrow().await?;
|
||||
let consumption = tibber.consumption(Daily, 1).await?;
|
||||
|
||||
let shared_db = Arc::new(Mutex::new(db));
|
||||
let tasmota_plugs: Vec<Tasmota> = devices
|
||||
|
|
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