wip: Add cli example. Change api macros.
This commit is contained in:
parent
3e62f354e8
commit
9cca1ca5bd
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
/target
|
||||
/Cargo.lock
|
||||
cli.json
|
||||
|
|
|
@ -26,3 +26,5 @@ regex = "1.5"
|
|||
|
||||
[dev-dependencies]
|
||||
test-log = { version = "0.2", default-features = false, features = ["trace"] }
|
||||
tracing-subscriber = "0.3"
|
||||
clap = { version = "3.2", features = ["derive", "env"]}
|
||||
|
|
|
@ -1,20 +1,36 @@
|
|||
use teslatte::auth::Authentication;
|
||||
use clap::Parser;
|
||||
use std::env;
|
||||
use teslatte::auth::{AccessToken, Authentication};
|
||||
use teslatte::vehicle_state::SetChargeLimit;
|
||||
use teslatte::Api;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt::init();
|
||||
|
||||
let api = Authentication::new().unwrap();
|
||||
let (access_token, refresh_token) = api.interactive_get_access_token().await.unwrap();
|
||||
println!("Access token: {}", access_token.0);
|
||||
println!("Refresh token: {}", refresh_token.0);
|
||||
let access_token = match env::var("TESLA_ACCESS_TOKEN") {
|
||||
Ok(t) => AccessToken(t),
|
||||
Err(_) => {
|
||||
let auth = Authentication::new().unwrap();
|
||||
let (access_token, refresh_token) = auth.interactive_get_access_token().await.unwrap();
|
||||
println!("Access token: {}", access_token.0);
|
||||
println!("Refresh token: {}", refresh_token.0);
|
||||
access_token
|
||||
}
|
||||
};
|
||||
|
||||
let api = Api::new(&access_token);
|
||||
|
||||
let vehicles = api.vehicles().await.unwrap();
|
||||
dbg!(&vehicles);
|
||||
|
||||
let charge_state = api.charge_state(&vehicles[0].id).await.unwrap();
|
||||
dbg!(&charge_state);
|
||||
if vehicles.len() > 0 {
|
||||
let vehicle_data = api.vehicle_data(&vehicles[0].id).await.unwrap();
|
||||
dbg!(vehicle_data);
|
||||
|
||||
let charge_state = api.charge_state(&vehicles[0].id).await.unwrap();
|
||||
dbg!(&charge_state);
|
||||
} else {
|
||||
println!("No vehicles found!");
|
||||
}
|
||||
}
|
||||
|
|
154
examples/cli.rs
Normal file
154
examples/cli.rs
Normal file
|
@ -0,0 +1,154 @@
|
|||
use clap::{Args, Parser, Subcommand};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use teslatte::auth::{AccessToken, Authentication, RefreshToken};
|
||||
use teslatte::vehicle_state::SetChargeLimit;
|
||||
use teslatte::{Api, Id};
|
||||
|
||||
const TESLA_ACCESS_TOKEN: &str = "TESLA_ACCESS_TOKEN";
|
||||
const TESLA_REFRESH_TOKEN: &str = "TESLA_REFRESH_TOKEN";
|
||||
|
||||
/// Teslatte
|
||||
///
|
||||
/// A command line interface for the Tesla API.
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(author, version, about, long_about = None)]
|
||||
struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Command,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum Command {
|
||||
/// Authenticate with Tesla via URL, and receive an access token and refresh token.
|
||||
Auth {
|
||||
/// Save tokens to a cli.json file.
|
||||
///
|
||||
/// Be careful with your access tokens!
|
||||
#[clap(short, long)]
|
||||
save: bool,
|
||||
},
|
||||
|
||||
/// Refresh your tokens.
|
||||
Refresh {
|
||||
/// If not provided, will try to read the token from a cli.json file and automatically
|
||||
/// update the file.
|
||||
#[clap(short, long, env = "TESLA_REFRESH_TOKEN")]
|
||||
refresh_token: Option<RefreshToken>,
|
||||
},
|
||||
|
||||
/// Run API commands.
|
||||
Api(ApiArgs),
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
struct ApiArgs {
|
||||
/// Access token. If not provided, will try to load from the cli.json file.
|
||||
#[clap(short, long, env = "TESLA_ACCESS_TOKEN")]
|
||||
access_token: Option<AccessToken>,
|
||||
|
||||
#[clap(subcommand)]
|
||||
command: ApiCommand,
|
||||
}
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
enum ApiCommand {
|
||||
/// Get a list of vehicles.
|
||||
Vehicles,
|
||||
|
||||
/// Get vehicle data.
|
||||
VehicleData { id: Id },
|
||||
|
||||
/// Get charge state.
|
||||
ChargeState { id: Id },
|
||||
|
||||
/// Set charge limit.
|
||||
SetChargeLimit { id: Id, percent: u8 },
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let args = Cli::parse();
|
||||
|
||||
match args.command {
|
||||
Command::Auth { save } => {
|
||||
let auth = Authentication::new().unwrap();
|
||||
let (access_token, refresh_token) = auth.interactive_get_access_token().await.unwrap();
|
||||
updated_tokens(save, access_token, refresh_token);
|
||||
}
|
||||
Command::Refresh { refresh_token } => {
|
||||
let (save, refresh_token) = match refresh_token {
|
||||
Some(refresh_token) => (false, refresh_token),
|
||||
None => {
|
||||
let config = Config::load();
|
||||
(true, config.refresh_token)
|
||||
}
|
||||
};
|
||||
|
||||
let auth = Authentication::new().unwrap();
|
||||
let response = auth.refresh_access_token(&refresh_token).await.unwrap();
|
||||
updated_tokens(save, response.access_token, refresh_token);
|
||||
}
|
||||
Command::Api(api_args) => {
|
||||
let access_token = match api_args.access_token {
|
||||
Some(a) => a,
|
||||
None => {
|
||||
let config = Config::load();
|
||||
config.access_token
|
||||
}
|
||||
};
|
||||
|
||||
let api = Api::new(&access_token);
|
||||
#[allow(unused_results)]
|
||||
match api_args.command {
|
||||
ApiCommand::Vehicles => {
|
||||
dbg!(api.vehicles().await.unwrap());
|
||||
}
|
||||
ApiCommand::VehicleData { id } => {
|
||||
dbg!(api.vehicle_data(&id).await.unwrap());
|
||||
}
|
||||
ApiCommand::ChargeState { id } => {
|
||||
dbg!(api.charge_state(&id).await.unwrap());
|
||||
}
|
||||
ApiCommand::SetChargeLimit { id, percent } => {
|
||||
dbg!(api
|
||||
.set_charge_limit(&id, &SetChargeLimit { percent })
|
||||
.await
|
||||
.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn updated_tokens(save: bool, access_token: AccessToken, refresh_token: RefreshToken) {
|
||||
println!("Access token: {}", access_token.0);
|
||||
println!("Refresh token: {}", refresh_token.0);
|
||||
if save {
|
||||
Config {
|
||||
access_token,
|
||||
refresh_token,
|
||||
}
|
||||
.save();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct Config {
|
||||
access_token: AccessToken,
|
||||
refresh_token: RefreshToken,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
fn save(&self) {
|
||||
let json = serde_json::to_string(&self).unwrap();
|
||||
std::fs::write("cli.json", json).unwrap();
|
||||
}
|
||||
|
||||
fn load() -> Self {
|
||||
let file = std::fs::File::open("cli.json").unwrap();
|
||||
let reader = std::io::BufReader::new(file);
|
||||
let json: serde_json::Value = serde_json::from_reader(reader).unwrap();
|
||||
let config: Config = serde_json::from_str(&json.to_string()).unwrap();
|
||||
config
|
||||
}
|
||||
}
|
15
src/auth.rs
15
src/auth.rs
|
@ -5,6 +5,7 @@ use reqwest::Client;
|
|||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::{stdin, stdout, Write};
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
|
||||
const AUTHORIZE_URL: &str = "https://auth.tesla.com/oauth2/v3/authorize";
|
||||
|
@ -17,9 +18,23 @@ pub struct Authentication {
|
|||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AccessToken(pub String);
|
||||
|
||||
impl FromStr for AccessToken {
|
||||
type Err = TeslatteError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(AccessToken(s.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct RefreshToken(pub String);
|
||||
|
||||
impl FromStr for RefreshToken {
|
||||
type Err = TeslatteError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(RefreshToken(s.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Authentication {
|
||||
pub fn new() -> Result<Self, TeslatteError> {
|
||||
let client = Client::builder()
|
||||
|
|
205
src/lib.rs
205
src/lib.rs
|
@ -1,12 +1,15 @@
|
|||
use crate::auth::AccessToken;
|
||||
use crate::error::TeslatteError;
|
||||
use miette::IntoDiagnostic;
|
||||
use reqwest::Client;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
pub mod auth;
|
||||
pub mod error;
|
||||
pub mod vehicle_state;
|
||||
|
||||
const API_URL: &str = "https://owner-api.teslamotors.com";
|
||||
|
||||
|
@ -16,6 +19,19 @@ const API_URL: &str = "https://owner-api.teslamotors.com";
|
|||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct Id(u64);
|
||||
|
||||
impl Display for Id {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Id {
|
||||
type Err = miette::Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Id(s.parse().into_diagnostic()?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Vehicle ID used by other endpoints.
|
||||
///
|
||||
/// This data comes from [`Api::vehicles()`] `vehicle_id` field.
|
||||
|
@ -44,10 +60,9 @@ impl Api {
|
|||
// I don't understand but it works: https://stackoverflow.com/a/60131725/11125
|
||||
D: for<'de> Deserialize<'de> + Debug,
|
||||
{
|
||||
trace!("Fetching");
|
||||
let url = format!("{}{}", API_URL, path);
|
||||
let request = || format!("GET {url}");
|
||||
debug!("Fetching");
|
||||
trace!(?url, "Fetching");
|
||||
let response = self
|
||||
.client
|
||||
.get(&url)
|
||||
|
@ -69,7 +84,7 @@ impl Api {
|
|||
})?;
|
||||
trace!(?body);
|
||||
|
||||
let json = Self::json::<D, _>(&body, request)?;
|
||||
let json = Self::parse_json::<D, _>(&body, request)?;
|
||||
trace!(?json);
|
||||
|
||||
Ok(json)
|
||||
|
@ -106,7 +121,7 @@ impl Api {
|
|||
source,
|
||||
request: request(),
|
||||
})?;
|
||||
let json = Self::json::<PostResponse, _>(&body, request)?;
|
||||
let json = Self::parse_json::<PostResponse, _>(&body, request)?;
|
||||
trace!(?json);
|
||||
|
||||
if json.result {
|
||||
|
@ -121,7 +136,7 @@ impl Api {
|
|||
}
|
||||
|
||||
// The `request` argument is for additional context in the error.
|
||||
fn json<T, F>(body: &str, request: F) -> Result<T, TeslatteError>
|
||||
fn parse_json<T, F>(body: &str, request: F) -> Result<T, TeslatteError>
|
||||
where
|
||||
T: for<'de> Deserialize<'de> + Debug,
|
||||
F: FnOnce() -> String + Copy,
|
||||
|
@ -182,152 +197,86 @@ struct ResponseError {
|
|||
error_description: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ChargeState {
|
||||
pub battery_heater_on: bool,
|
||||
pub battery_level: i64,
|
||||
pub battery_range: f64,
|
||||
pub charge_amps: i64,
|
||||
pub charge_current_request: i64,
|
||||
pub charge_current_request_max: i64,
|
||||
pub charge_enable_request: bool,
|
||||
pub charge_energy_added: f64,
|
||||
pub charge_limit_soc: i64,
|
||||
pub charge_limit_soc_max: i64,
|
||||
pub charge_limit_soc_min: i64,
|
||||
pub charge_limit_soc_std: i64,
|
||||
pub charge_miles_added_ideal: f64,
|
||||
pub charge_miles_added_rated: f64,
|
||||
pub charge_port_cold_weather_mode: bool,
|
||||
pub charge_port_color: String,
|
||||
pub charge_port_door_open: bool,
|
||||
pub charge_port_latch: String,
|
||||
pub charge_rate: f64,
|
||||
pub charge_to_max_range: bool,
|
||||
pub charger_actual_current: i64,
|
||||
pub charger_phases: Option<i64>,
|
||||
pub charger_pilot_current: i64,
|
||||
pub charger_power: i64,
|
||||
pub charger_voltage: i64,
|
||||
pub charging_state: String,
|
||||
pub conn_charge_cable: String,
|
||||
pub est_battery_range: f64,
|
||||
pub fast_charger_brand: String,
|
||||
pub fast_charger_present: bool,
|
||||
pub fast_charger_type: String,
|
||||
pub ideal_battery_range: f64,
|
||||
pub managed_charging_active: bool,
|
||||
pub managed_charging_start_time: Option<u64>,
|
||||
pub managed_charging_user_canceled: bool,
|
||||
pub max_range_charge_counter: i64,
|
||||
pub minutes_to_full_charge: i64,
|
||||
pub not_enough_power_to_heat: Option<bool>,
|
||||
pub off_peak_charging_enabled: bool,
|
||||
pub off_peak_charging_times: String,
|
||||
pub off_peak_hours_end_time: i64,
|
||||
pub preconditioning_enabled: bool,
|
||||
pub preconditioning_times: String,
|
||||
pub scheduled_charging_mode: String,
|
||||
pub scheduled_charging_pending: bool,
|
||||
pub scheduled_charging_start_time: Option<i64>,
|
||||
pub scheduled_charging_start_time_app: Option<i64>,
|
||||
pub scheduled_charging_start_time_minutes: Option<i64>,
|
||||
pub scheduled_departure_time: i64,
|
||||
pub scheduled_departure_time_minutes: i64,
|
||||
pub supercharger_session_trip_planner: bool,
|
||||
pub time_to_full_charge: f64,
|
||||
pub timestamp: u64,
|
||||
pub trip_charging: bool,
|
||||
pub usable_battery_level: i64,
|
||||
pub user_charge_enable_request: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Vehicles(Vec<Vehicle>);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Vehicle {
|
||||
pub id: Id,
|
||||
pub vehicle_id: VehicleId,
|
||||
pub vin: String,
|
||||
pub display_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct VehicleData {
|
||||
id: Id,
|
||||
user_id: u64,
|
||||
display_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SetChargingAmps {
|
||||
pub charging_amps: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SetChargeLimit {
|
||||
// pub percent: Percentage,
|
||||
pub percent: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct Empty {}
|
||||
|
||||
/// GET /api/1/vehicles/[id]/...
|
||||
/// GET /api/1/[url]
|
||||
macro_rules! get {
|
||||
($name:ident, $struct:ty, $url:expr) => {
|
||||
pub async fn $name(&self) -> Result<$struct, TeslatteError> {
|
||||
let url = format!("/api/1/vehicles{}", $url);
|
||||
($name:ident, $return_type:ty, $url:expr) => {
|
||||
pub async fn $name(&self) -> Result<$return_type, TeslatteError> {
|
||||
let url = format!("/api/1{}", $url);
|
||||
self.get(&url).await
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// GET /api/1/vehicles/[id]/...
|
||||
macro_rules! get_v {
|
||||
($name:ident, $struct:ty, $url:expr) => {
|
||||
pub async fn $name(&self, id: &Id) -> Result<$struct, TeslatteError> {
|
||||
let url = format!("/api/1/vehicles/{}{}", id.0, $url);
|
||||
/// GET /api/1/[url] with an argument.
|
||||
///
|
||||
/// Pass in the URL as a format string with one arg, which has to impl Display.
|
||||
macro_rules! get_arg {
|
||||
($name:ident, $return_type:ty, $url:expr, $arg_type:ty) => {
|
||||
pub async fn $name(&self, arg: &$arg_type) -> miette::Result<$return_type, TeslatteError> {
|
||||
let url = format!(concat!("/api/1", $url), arg);
|
||||
self.get(&url).await
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// POST /api/1/vehicles/[id]/... without data
|
||||
macro_rules! post_v {
|
||||
($name:ident, $url:expr) => {
|
||||
pub async fn $name(&self, id: &Id) -> miette::Result<(), TeslatteError> {
|
||||
let url = format!("/api/1/vehicles/{}{}", id.0, $url);
|
||||
self.post(&url, &Empty {}).await
|
||||
/// POST /api/1/[url] with an argument and data
|
||||
macro_rules! post_arg {
|
||||
($name:ident, $request_type:ty, $url:expr, $arg_type:ty) => {
|
||||
pub async fn $name(
|
||||
&self,
|
||||
arg: &$arg_type,
|
||||
data: &$request_type,
|
||||
) -> miette::Result<(), TeslatteError> {
|
||||
let url_fmt = format!($url, arg);
|
||||
let url = format!(concat!("/api/1", $url), arg);
|
||||
self.post(&url, data).await
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// POST /api/1/vehicles/[id]/... with data
|
||||
macro_rules! post_vd {
|
||||
($name:ident, $struct:ty, $url:expr) => {
|
||||
pub async fn $name(&self, id: &Id, data: &$struct) -> miette::Result<(), TeslatteError> {
|
||||
let url = format!("/api/1/vehicles/{}{}", id.0, $url);
|
||||
self.post(&url, &data).await
|
||||
}
|
||||
};
|
||||
}
|
||||
// /// POST /api/1/vehicles/[id]/... without data
|
||||
// macro_rules! post_v {
|
||||
// ($name:ident, $url:expr) => {
|
||||
// pub async fn $name(&self, id: &Id) -> miette::Result<(), TeslatteError> {
|
||||
// let url = format!("/vehicles/{}{}", id.0, $url);
|
||||
// self.post(&url, &Empty {}).await
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
//
|
||||
// /// POST /api/1/vehicles/[id]/... with data
|
||||
// macro_rules! post_vd {
|
||||
// ($name:ident, $struct:ty, $url:expr) => {
|
||||
// pub async fn $name(&self, id: &Id, data: &$struct) -> miette::Result<(), TeslatteError> {
|
||||
// let url = format!("/api/1/vehicles/{}{}", id.0, $url);
|
||||
// self.post(&url, &data).await
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
use crate::vehicle_state::ChargeState;
|
||||
use crate::vehicle_state::SetChargeLimit;
|
||||
use crate::vehicle_state::Vehicle;
|
||||
use crate::vehicle_state::VehicleData;
|
||||
|
||||
#[rustfmt::skip]
|
||||
impl Api {
|
||||
get!(vehicles, Vec<Vehicle>, "");
|
||||
get_v!(vehicle_data, VehicleData, "/vehicle_data");
|
||||
get_v!(charge_state, ChargeState, "/data_request/charge_state");
|
||||
post_vd!(set_charge_limit, SetChargeLimit, "/command/set_charge_limit");
|
||||
post_vd!(set_charging_amps, SetChargingAmps, "/command/set_charging_amps");
|
||||
post_v!(charge_start, "/command/charge_start");
|
||||
post_v!(charge_stop, "/command/charge_stop");
|
||||
get!(vehicles, Vec<Vehicle>, "/vehicles");
|
||||
get_arg!(vehicle_data, VehicleData, "/vehicles/{}/vehicle_data", Id);
|
||||
get_arg!(charge_state, ChargeState, "/vehicles/{}/data_request/charge_state", Id);
|
||||
post_arg!(set_charge_limit, SetChargeLimit, "/vehicles/{}/command/set_charge_limit", Id);
|
||||
// post_vd!(set_charging_amps, SetChargingAmps, "/command/set_charging_amps");
|
||||
// post_v!(charge_start, "/command/charge_start");
|
||||
// post_v!(charge_stop, "/command/charge_stop");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::vehicle_state::ChargeState;
|
||||
use test_log::test;
|
||||
|
||||
#[test]
|
||||
|
@ -394,7 +343,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
"#;
|
||||
Api::json::<ChargeState, _>(s, || "req".to_string()).unwrap();
|
||||
Api::parse_json::<ChargeState, _>(s, || "req".to_string()).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -403,7 +352,7 @@ mod tests {
|
|||
"response": null,
|
||||
"error":{"error": "timeout","error_description": "s"}
|
||||
}"#;
|
||||
let e = Api::json::<ChargeState, _>(s, || "req".to_string());
|
||||
let e = Api::parse_json::<ChargeState, _>(s, || "req".to_string());
|
||||
if let Err(e) = e {
|
||||
if let TeslatteError::ServerError {
|
||||
msg, description, ..
|
||||
|
|
306
src/vehicle_state.rs
Normal file
306
src/vehicle_state.rs
Normal file
|
@ -0,0 +1,306 @@
|
|||
/// Please note that these structs are generated from my own responses.
|
||||
///
|
||||
/// Sometimes the API will return a null for a field where I've put in a non Option type, which
|
||||
/// will cause the deserializer to fail. Please log an issue to fix these if you come across it.
|
||||
use crate::{Id, VehicleId};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct VehicleData {
|
||||
pub id: Id,
|
||||
pub user_id: i64,
|
||||
pub vehicle_id: VehicleId,
|
||||
pub vin: String,
|
||||
pub display_name: String,
|
||||
pub option_codes: String,
|
||||
/// gak: This was null for me, assuming String.
|
||||
pub color: Option<String>,
|
||||
pub access_type: String,
|
||||
pub tokens: Vec<String>,
|
||||
pub state: String,
|
||||
pub in_service: bool,
|
||||
pub id_s: String,
|
||||
pub calendar_enabled: bool,
|
||||
pub api_version: i64,
|
||||
/// gak: This was null for me, assuming String.
|
||||
pub backseat_token: Option<String>,
|
||||
/// gak: This was null for me, assuming String.
|
||||
pub backseat_token_updated_at: Option<String>,
|
||||
pub charge_state: ChargeState,
|
||||
pub climate_state: ClimateState,
|
||||
pub drive_state: DriveState,
|
||||
pub gui_settings: GuiSettings,
|
||||
pub vehicle_config: VehicleConfig,
|
||||
pub vehicle_state: VehicleState,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct ChargeState {
|
||||
pub battery_heater_on: bool,
|
||||
pub battery_level: i64,
|
||||
pub battery_range: f64,
|
||||
pub charge_amps: i64,
|
||||
pub charge_current_request: i64,
|
||||
pub charge_current_request_max: i64,
|
||||
pub charge_enable_request: bool,
|
||||
pub charge_energy_added: f64,
|
||||
pub charge_limit_soc: i64,
|
||||
pub charge_limit_soc_max: i64,
|
||||
pub charge_limit_soc_min: i64,
|
||||
pub charge_limit_soc_std: i64,
|
||||
pub charge_miles_added_ideal: f64,
|
||||
pub charge_miles_added_rated: f64,
|
||||
pub charge_port_cold_weather_mode: bool,
|
||||
pub charge_port_color: String,
|
||||
pub charge_port_door_open: bool,
|
||||
pub charge_port_latch: String,
|
||||
pub charge_rate: f64,
|
||||
pub charge_to_max_range: bool,
|
||||
pub charger_actual_current: i64,
|
||||
pub charger_phases: Option<i64>,
|
||||
pub charger_pilot_current: i64,
|
||||
pub charger_power: i64,
|
||||
pub charger_voltage: i64,
|
||||
pub charging_state: String,
|
||||
pub conn_charge_cable: String,
|
||||
pub est_battery_range: f64,
|
||||
pub fast_charger_brand: String,
|
||||
pub fast_charger_present: bool,
|
||||
pub fast_charger_type: String,
|
||||
pub ideal_battery_range: f64,
|
||||
pub managed_charging_active: bool,
|
||||
pub managed_charging_start_time: Option<u64>,
|
||||
pub managed_charging_user_canceled: bool,
|
||||
pub max_range_charge_counter: i64,
|
||||
pub minutes_to_full_charge: i64,
|
||||
pub not_enough_power_to_heat: Option<bool>,
|
||||
pub off_peak_charging_enabled: bool,
|
||||
pub off_peak_charging_times: String,
|
||||
pub off_peak_hours_end_time: i64,
|
||||
pub preconditioning_enabled: bool,
|
||||
pub preconditioning_times: String,
|
||||
pub scheduled_charging_mode: String,
|
||||
pub scheduled_charging_pending: bool,
|
||||
pub scheduled_charging_start_time: Option<i64>,
|
||||
pub scheduled_charging_start_time_app: Option<i64>,
|
||||
pub scheduled_charging_start_time_minutes: Option<i64>,
|
||||
pub scheduled_departure_time: i64,
|
||||
pub scheduled_departure_time_minutes: i64,
|
||||
pub supercharger_session_trip_planner: bool,
|
||||
pub time_to_full_charge: f64,
|
||||
pub timestamp: u64,
|
||||
pub trip_charging: bool,
|
||||
pub usable_battery_level: i64,
|
||||
pub user_charge_enable_request: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ClimateState {
|
||||
pub allow_cabin_overheat_protection: bool,
|
||||
pub auto_seat_climate_left: bool,
|
||||
pub auto_seat_climate_right: bool,
|
||||
pub battery_heater: bool,
|
||||
pub battery_heater_no_power: Option<bool>,
|
||||
pub cabin_overheat_protection: String,
|
||||
pub cabin_overheat_protection_actively_cooling: bool,
|
||||
pub climate_keeper_mode: String,
|
||||
pub defrost_mode: i64,
|
||||
pub driver_temp_setting: f64,
|
||||
pub fan_status: i64,
|
||||
pub hvac_auto_request: String,
|
||||
pub inside_temp: f64,
|
||||
pub is_auto_conditioning_on: bool,
|
||||
pub is_climate_on: bool,
|
||||
pub is_front_defroster_on: bool,
|
||||
pub is_preconditioning: bool,
|
||||
pub is_rear_defroster_on: bool,
|
||||
pub left_temp_direction: i64,
|
||||
pub max_avail_temp: f64,
|
||||
pub min_avail_temp: f64,
|
||||
pub outside_temp: f64,
|
||||
pub passenger_temp_setting: f64,
|
||||
pub remote_heater_control_enabled: bool,
|
||||
pub right_temp_direction: i64,
|
||||
pub seat_heater_left: i64,
|
||||
pub seat_heater_rear_center: i64,
|
||||
pub seat_heater_rear_left: i64,
|
||||
pub seat_heater_rear_right: i64,
|
||||
pub seat_heater_right: i64,
|
||||
pub side_mirror_heaters: bool,
|
||||
pub steering_wheel_heater: bool,
|
||||
pub supports_fan_only_cabin_overheat_protection: bool,
|
||||
pub timestamp: i64,
|
||||
pub wiper_blade_heater: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DriveState {
|
||||
pub gps_as_of: i64,
|
||||
pub heading: i64,
|
||||
pub latitude: f64,
|
||||
pub longitude: f64,
|
||||
pub native_latitude: f64,
|
||||
pub native_location_supported: i64,
|
||||
pub native_longitude: f64,
|
||||
pub native_type: String,
|
||||
pub power: i64,
|
||||
pub shift_state: Option<String>,
|
||||
/// gak: I've assumed this to be String.
|
||||
pub speed: Option<String>,
|
||||
pub timestamp: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GuiSettings {
|
||||
pub gui_24_hour_time: bool,
|
||||
pub gui_charge_rate_units: String,
|
||||
pub gui_distance_units: String,
|
||||
pub gui_range_display: String,
|
||||
pub gui_temperature_units: String,
|
||||
pub show_range_units: bool,
|
||||
pub timestamp: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VehicleConfig {
|
||||
pub aux_park_lamps: String,
|
||||
pub badge_version: i64,
|
||||
pub can_accept_navigation_requests: bool,
|
||||
pub can_actuate_trunks: bool,
|
||||
pub car_special_type: String,
|
||||
pub car_type: String,
|
||||
pub charge_port_type: String,
|
||||
pub dashcam_clip_save_supported: bool,
|
||||
pub default_charge_to_max: bool,
|
||||
pub driver_assist: String,
|
||||
pub ece_restrictions: bool,
|
||||
pub efficiency_package: String,
|
||||
pub eu_vehicle: bool,
|
||||
pub exterior_color: String,
|
||||
pub exterior_trim: String,
|
||||
pub exterior_trim_override: String,
|
||||
pub has_air_suspension: bool,
|
||||
pub has_ludicrous_mode: bool,
|
||||
pub has_seat_cooling: bool,
|
||||
pub headlamp_type: String,
|
||||
pub interior_trim_type: String,
|
||||
pub key_version: i64,
|
||||
pub motorized_charge_port: bool,
|
||||
pub paint_color_override: String,
|
||||
pub performance_package: String,
|
||||
pub plg: bool,
|
||||
pub pws: bool,
|
||||
pub rear_drive_unit: String,
|
||||
pub rear_seat_heaters: i64,
|
||||
pub rear_seat_type: i64,
|
||||
pub rhd: bool,
|
||||
pub roof_color: String,
|
||||
pub seat_type: Option<u32>,
|
||||
pub spoiler_type: String,
|
||||
pub sun_roof_installed: Option<u32>,
|
||||
pub supports_qr_pairing: bool,
|
||||
pub third_row_seats: String,
|
||||
pub timestamp: i64,
|
||||
pub trim_badging: String,
|
||||
pub use_range_badging: bool,
|
||||
pub utc_offset: i64,
|
||||
pub webcam_supported: bool,
|
||||
pub wheel_type: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VehicleState {
|
||||
pub api_version: i64,
|
||||
pub autopark_state_v2: String,
|
||||
pub autopark_style: String,
|
||||
pub calendar_supported: bool,
|
||||
pub car_version: String,
|
||||
pub center_display_state: i64,
|
||||
pub dashcam_clip_save_available: bool,
|
||||
pub dashcam_state: String,
|
||||
pub df: i64,
|
||||
pub dr: i64,
|
||||
pub fd_window: i64,
|
||||
pub feature_bitmask: String,
|
||||
pub fp_window: i64,
|
||||
pub ft: i64,
|
||||
pub is_user_present: bool,
|
||||
pub last_autopark_error: String,
|
||||
pub locked: bool,
|
||||
pub media_state: MediaState,
|
||||
pub notifications_supported: bool,
|
||||
pub odometer: f64,
|
||||
pub parsed_calendar_supported: bool,
|
||||
pub pf: i64,
|
||||
pub pr: i64,
|
||||
pub rd_window: i64,
|
||||
pub remote_start: bool,
|
||||
pub remote_start_enabled: bool,
|
||||
pub remote_start_supported: bool,
|
||||
pub rp_window: i64,
|
||||
pub rt: i64,
|
||||
pub santa_mode: i64,
|
||||
pub sentry_mode: bool,
|
||||
pub sentry_mode_available: bool,
|
||||
pub service_mode: bool,
|
||||
pub service_mode_plus: bool,
|
||||
pub smart_summon_available: bool,
|
||||
pub software_update: SoftwareUpdate,
|
||||
pub speed_limit_mode: SpeedLimitMode,
|
||||
pub summon_standby_mode_enabled: bool,
|
||||
pub timestamp: i64,
|
||||
pub tpms_pressure_fl: f64,
|
||||
pub tpms_pressure_fr: f64,
|
||||
pub tpms_pressure_rl: f64,
|
||||
pub tpms_pressure_rr: f64,
|
||||
pub valet_mode: bool,
|
||||
pub vehicle_name: String,
|
||||
pub vehicle_self_test_progress: i64,
|
||||
pub vehicle_self_test_requested: bool,
|
||||
pub webcam_available: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MediaState {
|
||||
pub remote_control_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SoftwareUpdate {
|
||||
pub download_perc: i64,
|
||||
pub expected_duration_sec: i64,
|
||||
pub install_perc: i64,
|
||||
pub status: String,
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SpeedLimitMode {
|
||||
pub active: bool,
|
||||
pub current_limit_mph: f64,
|
||||
pub max_limit_mph: i64,
|
||||
pub min_limit_mph: f64,
|
||||
pub pin_code_set: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Vehicles(Vec<Vehicle>);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Vehicle {
|
||||
pub id: Id,
|
||||
pub vehicle_id: VehicleId,
|
||||
pub vin: String,
|
||||
pub display_name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SetChargingAmps {
|
||||
pub charging_amps: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct SetChargeLimit {
|
||||
// pub percent: Percentage,
|
||||
pub percent: u8,
|
||||
}
|
Loading…
Reference in a new issue