vendored teslatte + some refactoring
This commit is contained in:
parent
b4a03f5e54
commit
f2e0bb6dc5
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
/test-config
|
||||||
|
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "vendored/teslatte"]
|
||||||
|
path = vendored/teslatte
|
||||||
|
url = https://github.com/gak/teslatte
|
55
Cargo.lock
generated
55
Cargo.lock
generated
|
@ -571,7 +571,7 @@ dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
"hyper",
|
"hyper",
|
||||||
"rustls",
|
"rustls 0.21.10",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
]
|
]
|
||||||
|
@ -1083,7 +1083,7 @@ dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"rustls",
|
"rustls 0.21.10",
|
||||||
"rustls-pemfile",
|
"rustls-pemfile",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -1163,10 +1163,24 @@ checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"ring",
|
"ring",
|
||||||
"rustls-webpki",
|
"rustls-webpki 0.101.7",
|
||||||
"sct",
|
"sct",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.22.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fe6b63262c9fcac8659abfaa96cac103d28166d3ff3eaf8f412e19f3ae9e5a48"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki 0.102.0",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-pemfile"
|
name = "rustls-pemfile"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -1176,6 +1190,12 @@ dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls-webpki"
|
name = "rustls-webpki"
|
||||||
version = "0.101.7"
|
version = "0.101.7"
|
||||||
|
@ -1186,6 +1206,17 @@ dependencies = [
|
||||||
"untrusted",
|
"untrusted",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.102.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "de2635c8bc2b88d367767c5de8ea1d8db9af3f6219eba28442242d9ab81d1b89"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
|
@ -1389,6 +1420,12 @@ dependencies = [
|
||||||
"syn 2.0.43",
|
"syn 2.0.43",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "supports-color"
|
name = "supports-color"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
|
@ -1498,8 +1535,6 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "teslatte"
|
name = "teslatte"
|
||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "caf300415380acad835db51dc04d5f331dfab81aa24e425d7da39af5d17b0830"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
@ -1509,7 +1544,7 @@ dependencies = [
|
||||||
"pkce",
|
"pkce",
|
||||||
"rand",
|
"rand",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rustls",
|
"rustls 0.22.1",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"strum",
|
"strum",
|
||||||
|
@ -1652,7 +1687,7 @@ version = "0.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls 0.21.10",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2100,3 +2135,9 @@ name = "yansi"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||||
|
|
|
@ -28,5 +28,5 @@ clap = { version = "4.0", features = ["derive"] }
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tokio = { version = "1.35.1", features = ["full"] }
|
tokio = { version = "1.35.1", features = ["full"] }
|
||||||
teslatte = "0.1.11"
|
teslatte = { path = "vendored/teslatte" }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
3
src/control.rs
Normal file
3
src/control.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
use teslatte::OwnerApi;
|
||||||
|
|
||||||
|
pub async fn control_loop(_api: OwnerApi) {}
|
|
@ -1,18 +1,40 @@
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum SaveError {
|
||||||
|
#[error("stdio error")]
|
||||||
|
StdIo(#[from] std::io::Error),
|
||||||
|
#[error("ron")]
|
||||||
|
RonSpanned(#[from] ron::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SaveError {
|
||||||
|
pub fn error_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
SaveError::StdIo(e) => format!("Error reading access token from disk: {e:?}"),
|
||||||
|
SaveError::RonSpanned(e) => format!("Error deserialising access token: {e:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum AuthLoadError {
|
pub enum AuthLoadError {
|
||||||
#[error("stdio error")]
|
#[error("stdio error")]
|
||||||
StdIo(#[from] std::io::Error),
|
StdIo(#[from] std::io::Error),
|
||||||
#[error("ron - spanned error")]
|
#[error("ron - spanned error")]
|
||||||
RonSpanned(#[from] ron::error::SpannedError),
|
RonSpanned(#[from] ron::error::SpannedError),
|
||||||
|
#[error("teslatte error")]
|
||||||
|
Teslatte(#[from] teslatte::error::TeslatteError),
|
||||||
|
#[error("save error")]
|
||||||
|
Save(#[from] SaveError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AuthLoadError {
|
impl AuthLoadError {
|
||||||
pub fn error_string(&self) -> String {
|
pub fn error_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
AuthLoadError::Teslatte(e) => format!("Error refreshing access token: {e:?}"),
|
||||||
AuthLoadError::StdIo(e) => format!("Error reading access token from disk: {e:?}"),
|
AuthLoadError::StdIo(e) => format!("Error reading access token from disk: {e:?}"),
|
||||||
AuthLoadError::RonSpanned(e) => format!("Error deserialising access token: {e:?}"),
|
AuthLoadError::RonSpanned(e) => format!("Error deserialising access token: {e:?}"),
|
||||||
|
AuthLoadError::Save(e) => e.error_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,18 +43,15 @@ impl AuthLoadError {
|
||||||
pub enum LoginError {
|
pub enum LoginError {
|
||||||
#[error("teslatte error")]
|
#[error("teslatte error")]
|
||||||
Teslatte(#[from] teslatte::error::TeslatteError),
|
Teslatte(#[from] teslatte::error::TeslatteError),
|
||||||
#[error("ron error")]
|
#[error("save error")]
|
||||||
Ron(#[from] ron::Error),
|
Save(#[from] SaveError),
|
||||||
#[error("stdio error")]
|
|
||||||
StdIo(#[from] std::io::Error),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LoginError {
|
impl LoginError {
|
||||||
pub fn error_string(&self) -> String {
|
pub fn error_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
LoginError::Teslatte(e) => format!("Authentication flow error: {e:?}"),
|
LoginError::Teslatte(e) => format!("Authentication flow error: {e:?}"),
|
||||||
LoginError::Ron(e) => format!("Error serialising access token: {e:?}"),
|
LoginError::Save(e) => e.error_string(),
|
||||||
LoginError::StdIo(e) => format!("Error saving access token to disk: {e:?}"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
63
src/main.rs
63
src/main.rs
|
@ -1,10 +1,15 @@
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{io::BufRead, path::PathBuf};
|
use std::{io::BufRead, path::PathBuf};
|
||||||
use teslatte::{auth::AccessToken, OwnerApi};
|
use teslatte::{
|
||||||
|
auth::{AccessToken, RefreshToken},
|
||||||
|
OwnerApi, VehicleApi,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{config::Config, errors::*};
|
use crate::{config::Config, errors::*};
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
|
mod control;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
|
||||||
#[derive(Parser, Debug, Clone)]
|
#[derive(Parser, Debug, Clone)]
|
||||||
|
@ -19,7 +24,10 @@ struct Args {
|
||||||
#[derive(Subcommand, Debug, Clone)]
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
enum Commands {
|
enum Commands {
|
||||||
/// Run charge controller server
|
/// Run charge controller server
|
||||||
Watch,
|
Watch {
|
||||||
|
#[clap(long)]
|
||||||
|
flash: bool,
|
||||||
|
},
|
||||||
/// Authenticate with Tesla login
|
/// Authenticate with Tesla login
|
||||||
Auth,
|
Auth,
|
||||||
/// Print the default config file
|
/// Print the default config file
|
||||||
|
@ -43,7 +51,7 @@ fn press_y_to_continue() -> bool {
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let auth_path = args.config_dir.join("auth");
|
let auth_path = args.config_dir.join("auth");
|
||||||
let config_path = args.config_dir.join("config");
|
// let config_path = args.config_dir.join("config");
|
||||||
|
|
||||||
match args.command {
|
match args.command {
|
||||||
Commands::GenerateConfig => {
|
Commands::GenerateConfig => {
|
||||||
|
@ -63,24 +71,61 @@ async fn main() {
|
||||||
println!("{}", e.error_string());
|
println!("{}", e.error_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Commands::Watch => match get_auth(auth_path) {
|
Commands::Watch { flash } => match get_auth(auth_path).await {
|
||||||
Ok(api) => {
|
Ok(api) => {
|
||||||
println!("got products: {:#?}", api.products().await)
|
let products = api.products().await;
|
||||||
|
println!("got products: {:#?}", products);
|
||||||
|
if flash {
|
||||||
|
if let Ok(res) = products {
|
||||||
|
if let Some(teslatte::products::Product::Vehicle(vehicle)) = res.first() {
|
||||||
|
let _ = api.honk_horn(&vehicle.id).await;
|
||||||
|
match api.flash_lights(&vehicle.id).await {
|
||||||
|
Ok(_r) => println!("flashed"),
|
||||||
|
Err(e) => println!("error: {e:#?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
control::control_loop(api).await;
|
||||||
}
|
}
|
||||||
Err(e) => println!("{}", e.error_string()),
|
Err(e) => println!("{}", e.error_string()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_auth(auth_path: PathBuf) -> Result<OwnerApi, AuthLoadError> {
|
async fn get_auth(auth_path: PathBuf) -> Result<OwnerApi, AuthLoadError> {
|
||||||
let key: AccessToken = ron::from_str(&std::fs::read_to_string(auth_path)?)?;
|
let key: AuthInfo = ron::from_str(&std::fs::read_to_string(&auth_path)?)?;
|
||||||
Ok(OwnerApi::new(key, None))
|
let mut api = OwnerApi::new(key.access_token, key.refresh_token);
|
||||||
|
api.refresh().await?;
|
||||||
|
println!("Refreshed auth key");
|
||||||
|
save_key(auth_path, &api)?;
|
||||||
|
Ok(api)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct AuthInfo {
|
||||||
|
access_token: AccessToken,
|
||||||
|
refresh_token: Option<RefreshToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn log_in(auth_path: PathBuf) -> Result<(), LoginError> {
|
async fn log_in(auth_path: PathBuf) -> Result<(), LoginError> {
|
||||||
let v = OwnerApi::from_interactive_url().await?;
|
let v = OwnerApi::from_interactive_url().await?;
|
||||||
|
|
||||||
std::fs::write(auth_path, ron::ser::to_string(&v.access_token)?)?;
|
let products = v.products().await;
|
||||||
|
println!("got products: {:#?}", products);
|
||||||
|
|
||||||
|
save_key(auth_path, &v)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn save_key(auth_path: PathBuf, api: &OwnerApi) -> Result<(), SaveError> {
|
||||||
|
std::fs::write(
|
||||||
|
auth_path,
|
||||||
|
ron::ser::to_string(&AuthInfo {
|
||||||
|
access_token: api.access_token.clone(),
|
||||||
|
refresh_token: api.refresh_token.clone(),
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
println!("Auth successfully saved");
|
println!("Auth successfully saved");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
1
vendored/teslatte
Submodule
1
vendored/teslatte
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 491d9a58a8183b91314990274da805c156a6f48c
|
Loading…
Reference in a new issue