Skip to content

Commit

Permalink
Merge pull request #8 from gak/7-refactor-api
Browse files Browse the repository at this point in the history
  • Loading branch information
gak authored Oct 21, 2023
2 parents a0cc8bf + 8c05976 commit 39627f3
Show file tree
Hide file tree
Showing 12 changed files with 303 additions and 195 deletions.
14 changes: 7 additions & 7 deletions examples/basic.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use std::env;
use teslatte::auth::AccessToken;
use teslatte::products::Product;
use teslatte::Api;
use teslatte::{OwnerApi, VehicleApi};

#[tokio::main]
async fn main() {
tracing_subscriber::fmt::init();

let api = match env::var("TESLA_ACCESS_TOKEN") {
Ok(t) => Api::new(AccessToken(t), None),
Ok(t) => OwnerApi::new(AccessToken(t), None),
Err(_) => {
let api = Api::from_interactive_url().await.unwrap();
let api = OwnerApi::from_interactive_url().await.unwrap();
println!("TOKEN: {:?}", api.access_token);
api
}
Expand All @@ -21,7 +21,7 @@ async fn main() {

if !vehicles.is_empty() {
let vehicle_data = api.vehicle_data(&vehicles[0].id).await.unwrap();
dbg!(&*vehicle_data);
dbg!(&vehicle_data);
} else {
println!("No vehicles found!");
}
Expand All @@ -38,21 +38,21 @@ async fn main() {

Product::Solar(e) => {
let site_info = api.energy_sites_site_info(&e.energy_site_id).await.unwrap();
dbg!(&*site_info);
dbg!(&site_info);

let live_info = api
.energy_sites_live_status(&e.energy_site_id)
.await
.unwrap();
dbg!(&*live_info);
dbg!(&live_info);
}

Product::Powerwall(p) => {
let live_info = api
.energy_sites_live_status(&p.energy_site_id)
.await
.unwrap();
dbg!(&*live_info);
dbg!(&live_info);
}
}
}
Expand Down
22 changes: 12 additions & 10 deletions src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::error::TeslatteError::{CouldNotFindCallbackCode, CouldNotFindState};
use crate::{Api, TeslatteError};
use crate::{OwnerApi, TeslatteError};
use derive_more::{Display, FromStr};
use rand::Rng;
use reqwest::Client;
Expand All @@ -22,11 +22,11 @@ struct Callback {
state: String,
}

impl Api {
impl OwnerApi {
/// Show a URL for the user to click on to log into tesla.com, the ask them to paste the
/// URL they end up on, which is a 404 page. The URL contains OAuth information needed to
/// complete authentication for an access key.
pub async fn from_interactive_url() -> Result<Api, TeslatteError> {
pub async fn from_interactive_url() -> Result<OwnerApi, TeslatteError> {
let login_form = Self::get_login_url_for_user().await;
println!("{}", "-".repeat(80));
println!("{}", login_form.url);
Expand All @@ -40,12 +40,12 @@ page, where the URL will start with https://auth.tesla.com/void/callback?code=..
let callback_url = ask_input("Enter the whole URL of the 404 page: ");
println!(); // Newline to make the next output more separated and clear.

Api::from_callback_url(&login_form, &callback_url).await
OwnerApi::from_callback_url(&login_form, &callback_url).await
}

/// Generate a [LoginForm] containing a URL the user should visit.
///
/// See [Api::from_callback_url()] for the next step.
/// See [OwnerApi::from_callback_url()] for the next step.
pub async fn get_login_url_for_user() -> LoginForm {
let code = Code::new();
let state = random_string(8);
Expand All @@ -54,11 +54,11 @@ page, where the URL will start with https://auth.tesla.com/void/callback?code=..
}

/// Parse a callback URL that the user was redirected to after logging in via
/// [Api::from_interactive_url()].
/// [OwnerApi::from_interactive_url()].
pub async fn from_callback_url(
login_form: &LoginForm,
callback_url: &str,
) -> Result<Api, TeslatteError> {
) -> Result<OwnerApi, TeslatteError> {
let callback = Self::extract_callback_from_url(callback_url)?;
if callback.state != login_form.state {
return Err(TeslatteError::StateMismatch {
Expand All @@ -70,12 +70,14 @@ page, where the URL will start with https://auth.tesla.com/void/callback?code=..
let bearer = Self::exchange_auth_for_bearer(&login_form.code, &callback.code).await?;
let access_token = AccessToken(bearer.access_token);
let refresh_token = RefreshToken(bearer.refresh_token);
Ok(Api::new(access_token, Some(refresh_token)))
Ok(OwnerApi::new(access_token, Some(refresh_token)))
}

pub async fn from_refresh_token(refresh_token: &RefreshToken) -> Result<Api, TeslatteError> {
pub async fn from_refresh_token(
refresh_token: &RefreshToken,
) -> Result<OwnerApi, TeslatteError> {
let response = Self::refresh_token(refresh_token).await?;
Ok(Api::new(
Ok(OwnerApi::new(
response.access_token,
Some(response.refresh_token),
))
Expand Down
34 changes: 0 additions & 34 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,3 @@
pub mod energy;
pub mod powerwall;
pub mod vehicle;

use crate::error::TeslatteError;
use crate::ResponseData;
use std::process::exit;

pub fn print_json<T>(result: Result<ResponseData<T>, TeslatteError>) {
match result {
Ok(data) => print_json_data(data),
Err(TeslatteError::ServerError { ref body, .. }) if body.is_some() => {
print_json_str(&body.clone().unwrap())
}
Err(e) => {
eprintln!("{}", e);
exit(1);
}
}
}
pub fn print_json_data<T>(data: ResponseData<T>) {
// TODO: pretty print cli option
print_json_str(data.body());
}

pub fn print_json_str(body: &str) {
#[cfg(feature = "cli-pretty-json")]
{
use colored_json::prelude::*;
println!("{}", body.to_colored_json_auto().unwrap());
}

#[cfg(not(feature = "cli-pretty-json"))]
{
println!("{}", body);
}
}
13 changes: 6 additions & 7 deletions src/cli/energy.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::cli::print_json;
use crate::energy_sites::{CalendarHistoryValues, HistoryKind, HistoryPeriod};
use crate::products::EnergySiteId;
use crate::Api;
use crate::OwnerApi;
use chrono::DateTime;
use clap::{Args, Subcommand};
use miette::{IntoDiagnostic, WrapErr};
Expand All @@ -23,16 +22,16 @@ pub struct EnergySiteArgs {
}

impl EnergySiteArgs {
pub async fn run(&self, api: &Api) -> miette::Result<()> {
pub async fn run(&self, api: &OwnerApi) -> miette::Result<()> {
match &self.command {
EnergySiteCommand::SiteStatus => {
print_json(api.energy_sites_site_status(&self.id).await);
api.energy_sites_site_status(&self.id).await?;
}
EnergySiteCommand::LiveStatus => {
print_json(api.energy_sites_live_status(&self.id).await);
api.energy_sites_live_status(&self.id).await?;
}
EnergySiteCommand::SiteInfo => {
print_json(api.energy_sites_site_info(&self.id).await);
api.energy_sites_site_info(&self.id).await?;
}
EnergySiteCommand::CalendarHistory(args) => {
let start_date = args
Expand All @@ -54,7 +53,7 @@ impl EnergySiteArgs {
start_date,
end_date,
};
print_json(api.energy_sites_calendar_history(&values).await);
api.energy_sites_calendar_history(&values).await?;
}
}
Ok(())
Expand Down
25 changes: 11 additions & 14 deletions src/cli/powerwall.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::cli::print_json_data;
use crate::energy_sites::{HistoryKind, HistoryPeriod};
use crate::powerwall::{PowerwallEnergyHistoryValues, PowerwallId};
use crate::Api;
use crate::OwnerApi;
use clap::{Args, Subcommand};

#[derive(Debug, Subcommand)]
Expand All @@ -21,22 +20,20 @@ pub struct PowerwallArgs {
}

impl PowerwallArgs {
pub async fn run(&self, api: &Api) -> miette::Result<()> {
pub async fn run(&self, api: &OwnerApi) -> miette::Result<()> {
match self.command {
PowerwallCommand::Status => {
print_json_data(api.powerwall_status(&self.id).await?);
api.powerwall_status(&self.id).await?;
}
PowerwallCommand::History => {
print_json_data(
api.powerwall_energy_history(&PowerwallEnergyHistoryValues {
powerwall_id: self.id.clone(),
period: HistoryPeriod::Day,
kind: HistoryKind::Power,
start_date: None,
end_date: None,
})
.await?,
);
api.powerwall_energy_history(&PowerwallEnergyHistoryValues {
powerwall_id: self.id.clone(),
period: HistoryPeriod::Day,
kind: HistoryKind::Power,
start_date: None,
end_date: None,
})
.await?;
}
}
Ok(())
Expand Down
43 changes: 21 additions & 22 deletions src/cli/vehicle.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::cli::print_json;
use crate::vehicles::{
SetChargeLimit, SetChargingAmps, SetScheduledCharging, SetScheduledDeparture, SetTemperatures,
};
use crate::{Api, VehicleId};
use crate::{OwnerApi, VehicleApi, VehicleId};
use clap::{Args, Subcommand};

#[derive(Debug, Subcommand)]
Expand Down Expand Up @@ -74,64 +73,64 @@ pub struct VehicleArgs {
}

impl VehicleArgs {
pub async fn run(self, api: &Api) -> miette::Result<()> {
pub async fn run(self, api: &OwnerApi) -> miette::Result<()> {
match self.command {
VehicleCommand::VehicleData => {
print_json(api.vehicle_data(&self.id).await);
api.vehicle_data(&self.id).await?;
}
VehicleCommand::SetChargeLimit(limit) => {
print_json(api.set_charge_limit(&self.id, &limit).await);
api.set_charge_limit(&self.id, &limit).await?;
}
VehicleCommand::SetChargingAmps(charging_amps) => {
print_json(api.set_charging_amps(&self.id, &charging_amps).await);
api.set_charging_amps(&self.id, &charging_amps).await?;
}
VehicleCommand::ChargeStart => {
print_json(api.charge_start(&self.id).await);
api.charge_start(&self.id).await?;
}
VehicleCommand::ChargeStop => {
print_json(api.charge_stop(&self.id).await);
api.charge_stop(&self.id).await?;
}
VehicleCommand::ChargePortDoorOpen => {
print_json(api.charge_port_door_open(&self.id).await);
api.charge_port_door_open(&self.id).await?;
}
VehicleCommand::ChargePortDoorClose => {
print_json(api.charge_port_door_close(&self.id).await);
api.charge_port_door_close(&self.id).await?;
}
VehicleCommand::ChargeStandard => {
print_json(api.charge_standard(&self.id).await);
api.charge_standard(&self.id).await?;
}
VehicleCommand::ChargeMaxRange => {
print_json(api.charge_max_range(&self.id).await);
api.charge_max_range(&self.id).await?;
}
VehicleCommand::SetScheduledCharging(charging) => {
print_json(api.set_scheduled_charging(&self.id, &charging).await);
api.set_scheduled_charging(&self.id, &charging).await?;
}
VehicleCommand::SetScheduledDeparture(departure) => {
print_json(api.set_scheduled_departure(&self.id, &departure).await);
api.set_scheduled_departure(&self.id, &departure).await?;
}
VehicleCommand::HonkHorn => {
print_json(api.honk_horn(&self.id).await);
api.honk_horn(&self.id).await?;
}
VehicleCommand::FlashLights => {
print_json(api.flash_lights(&self.id).await);
api.flash_lights(&self.id).await?;
}
VehicleCommand::EnableHvac => {
print_json(api.auto_conditioning_start(&self.id).await);
api.auto_conditioning_start(&self.id).await?;
}
VehicleCommand::DisableHvac => {
print_json(api.auto_conditioning_stop(&self.id).await);
api.auto_conditioning_stop(&self.id).await?;
}
VehicleCommand::HvacTemperature(temps) => {
print_json(api.set_temps(&self.id, &temps).await);
api.set_temps(&self.id, &temps).await?;
}
VehicleCommand::DoorUnlock => {
print_json(api.door_unlock(&self.id).await);
api.door_unlock(&self.id).await?;
}
VehicleCommand::DoorLock => {
print_json(api.door_lock(&self.id).await);
api.door_lock(&self.id).await?;
}
VehicleCommand::RemoteStartDrive => {
print_json(api.remote_start_drive(&self.id).await);
api.remote_start_drive(&self.id).await?;
}
}
Ok(())
Expand Down
18 changes: 10 additions & 8 deletions src/energy_sites.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use crate::products::EnergySiteId;
use crate::{get_arg, get_args, join_query_pairs, rfc3339, Api, Values};
use crate::{join_query_pairs, pub_get_arg, pub_get_args, rfc3339, OwnerApi, Values};
use chrono::{DateTime, FixedOffset};
use serde::Deserialize;
use strum::{Display, EnumString, IntoStaticStr};

#[rustfmt::skip]
impl Api {
get_arg!(energy_sites_site_status, SiteStatus, "/energy_sites/{}/site_status", EnergySiteId);
get_arg!(energy_sites_live_status, LiveStatus, "/energy_sites/{}/live_status", EnergySiteId);
get_arg!(energy_sites_site_info, SiteInfo, "/energy_sites/{}/site_info", EnergySiteId);
get_args!(energy_sites_calendar_history, CalendarHistory, "/energy_sites/{}/calendar_history", CalendarHistoryValues);
impl OwnerApi {
pub_get_arg!(energy_sites_site_status, SiteStatus, "/energy_sites/{}/site_status", EnergySiteId);
pub_get_arg!(energy_sites_live_status, LiveStatus, "/energy_sites/{}/live_status", EnergySiteId);
pub_get_arg!(energy_sites_site_info, SiteInfo, "/energy_sites/{}/site_info", EnergySiteId);
pub_get_args!(energy_sites_calendar_history, CalendarHistory, "/energy_sites/{}/calendar_history", CalendarHistoryValues);
}

#[derive(Debug, Clone, Deserialize)]
Expand All @@ -22,8 +22,10 @@ pub struct SiteStatus {
pub gateway_id: String,
pub percentage_charged: f64,
pub powerwall_onboarding_settings_set: bool,
pub powerwall_tesla_electric_interested_in: Option<()>, // TODO: Unknown type. Was null.
pub resource_type: String, // battery
// TODO: Unknown type. Was null.
pub powerwall_tesla_electric_interested_in: Option<()>,
// battery
pub resource_type: String,
pub site_name: String,
pub storm_mode_enabled: bool,
pub sync_grid_alert_enabled: bool,
Expand Down
Loading

0 comments on commit 39627f3

Please sign in to comment.