feat: cli show json on POST and some errors
This commit is contained in:
parent
3fd59df8b8
commit
900be5aa1f
25
src/cli.rs
25
src/cli.rs
|
@ -2,17 +2,36 @@ pub mod energy;
|
||||||
pub mod powerwall;
|
pub mod powerwall;
|
||||||
pub mod vehicle;
|
pub mod vehicle;
|
||||||
|
|
||||||
|
use crate::error::TeslatteError;
|
||||||
use crate::Data;
|
use crate::Data;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
pub fn print_json<T>(data: Data<T>) {
|
pub fn print_json<T>(result: Result<Data<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: Data<T>) {
|
||||||
|
// TODO: pretty print cli option
|
||||||
|
print_json_str(data.body());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn print_json_str(body: &str) {
|
||||||
#[cfg(feature = "cli-pretty-json")]
|
#[cfg(feature = "cli-pretty-json")]
|
||||||
{
|
{
|
||||||
use colored_json::prelude::*;
|
use colored_json::prelude::*;
|
||||||
println!("{}", data.body().to_colored_json_auto().unwrap());
|
println!("{}", body.to_colored_json_auto().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "cli-pretty-json"))]
|
#[cfg(not(feature = "cli-pretty-json"))]
|
||||||
{
|
{
|
||||||
println!("{}", data.body());
|
println!("{}", body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ impl EnergySiteArgs {
|
||||||
start_date,
|
start_date,
|
||||||
end_date,
|
end_date,
|
||||||
};
|
};
|
||||||
print_json(api.energy_sites_calendar_history(&values).await?);
|
print_json(api.energy_sites_calendar_history(&values).await);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::calendar_history::{HistoryKind, HistoryPeriod};
|
use crate::calendar_history::{HistoryKind, HistoryPeriod};
|
||||||
use crate::cli::print_json;
|
use crate::cli::print_json_data;
|
||||||
use crate::powerwall::{PowerwallEnergyHistoryValues, PowerwallId};
|
use crate::powerwall::{PowerwallEnergyHistoryValues, PowerwallId};
|
||||||
use crate::Api;
|
use crate::Api;
|
||||||
use clap::{Args, Subcommand};
|
use clap::{Args, Subcommand};
|
||||||
|
@ -24,10 +24,10 @@ impl PowerwallArgs {
|
||||||
pub async fn run(&self, api: &Api) -> miette::Result<()> {
|
pub async fn run(&self, api: &Api) -> miette::Result<()> {
|
||||||
match self.command {
|
match self.command {
|
||||||
PowerwallCommand::Status => {
|
PowerwallCommand::Status => {
|
||||||
print_json(api.powerwall_status(&self.id).await?);
|
print_json_data(api.powerwall_status(&self.id).await?);
|
||||||
}
|
}
|
||||||
PowerwallCommand::History => {
|
PowerwallCommand::History => {
|
||||||
print_json(
|
print_json_data(
|
||||||
api.powerwall_energy_history(&PowerwallEnergyHistoryValues {
|
api.powerwall_energy_history(&PowerwallEnergyHistoryValues {
|
||||||
powerwall_id: self.id.clone(),
|
powerwall_id: self.id.clone(),
|
||||||
period: HistoryPeriod::Day,
|
period: HistoryPeriod::Day,
|
||||||
|
|
|
@ -36,24 +36,28 @@ impl VehicleArgs {
|
||||||
pub async fn run(self, api: &Api) -> miette::Result<()> {
|
pub async fn run(self, api: &Api) -> miette::Result<()> {
|
||||||
match self.command {
|
match self.command {
|
||||||
VehicleCommand::Data => {
|
VehicleCommand::Data => {
|
||||||
print_json(api.vehicle_data(&self.id).await?);
|
print_json(api.vehicle_data(&self.id).await);
|
||||||
}
|
}
|
||||||
VehicleCommand::ChargeState => {
|
VehicleCommand::ChargeState => {
|
||||||
print_json(api.charge_state(&self.id).await?);
|
print_json(api.charge_state(&self.id).await);
|
||||||
}
|
}
|
||||||
VehicleCommand::SetChargeLimit { percent } => {
|
VehicleCommand::SetChargeLimit { percent } => {
|
||||||
|
print_json(
|
||||||
api.set_charge_limit(&self.id, &SetChargeLimit { percent })
|
api.set_charge_limit(&self.id, &SetChargeLimit { percent })
|
||||||
.await?;
|
.await,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
VehicleCommand::SetChargingAmps { charging_amps } => {
|
VehicleCommand::SetChargingAmps { charging_amps } => {
|
||||||
|
print_json(
|
||||||
api.set_charging_amps(&self.id, &SetChargingAmps { charging_amps })
|
api.set_charging_amps(&self.id, &SetChargingAmps { charging_amps })
|
||||||
.await?;
|
.await,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
VehicleCommand::ChargeStart => {
|
VehicleCommand::ChargeStart => {
|
||||||
api.charge_start(&self.id).await?;
|
print_json(api.charge_start(&self.id).await);
|
||||||
}
|
}
|
||||||
VehicleCommand::ChargeStop => {
|
VehicleCommand::ChargeStop => {
|
||||||
api.charge_stop(&self.id).await?;
|
print_json(api.charge_stop(&self.id).await);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub enum TeslatteError {
|
||||||
request: String,
|
request: String,
|
||||||
msg: String,
|
msg: String,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
|
body: Option<String>,
|
||||||
},
|
},
|
||||||
|
|
||||||
#[error("{request} unhandled server response: {body}")]
|
#[error("{request} unhandled server response: {body}")]
|
||||||
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -89,7 +89,7 @@ impl Api {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self))]
|
#[instrument(skip(self))]
|
||||||
async fn post<S>(&self, url: &str, body: S) -> Result<(), TeslatteError>
|
async fn post<S>(&self, url: &str, body: S) -> Result<Data<PostResponse>, TeslatteError>
|
||||||
where
|
where
|
||||||
S: Serialize + Debug,
|
S: Serialize + Debug,
|
||||||
{
|
{
|
||||||
|
@ -122,16 +122,17 @@ impl Api {
|
||||||
source,
|
source,
|
||||||
request: req_ctx(),
|
request: req_ctx(),
|
||||||
})?;
|
})?;
|
||||||
let json = Self::parse_json::<PostResponse, _>(&body, req_ctx)?;
|
let data = Self::parse_json::<PostResponse, _>(&body, req_ctx)?;
|
||||||
trace!(?json);
|
trace!(?data);
|
||||||
|
|
||||||
if json.result {
|
if data.result {
|
||||||
Ok(())
|
Ok(Data { data, body })
|
||||||
} else {
|
} else {
|
||||||
Err(TeslatteError::ServerError {
|
Err(TeslatteError::ServerError {
|
||||||
request: req_ctx(),
|
request: req_ctx(),
|
||||||
msg: json.reason,
|
msg: data.reason,
|
||||||
description: None,
|
description: None,
|
||||||
|
body: Some(body),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,6 +158,7 @@ impl Api {
|
||||||
request: request(),
|
request: request(),
|
||||||
msg: e.error,
|
msg: e.error,
|
||||||
description: e.error_description,
|
description: e.error_description,
|
||||||
|
body: Some(body.to_owned()),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,7 +189,7 @@ impl<T> From<ResponseDeserializer<T>> for Response<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct PostResponse {
|
pub struct PostResponse {
|
||||||
reason: String,
|
reason: String,
|
||||||
result: bool,
|
result: bool,
|
||||||
}
|
}
|
||||||
|
@ -281,7 +283,7 @@ macro_rules! post_arg {
|
||||||
&self,
|
&self,
|
||||||
arg: &$arg_type,
|
arg: &$arg_type,
|
||||||
data: &$request_type,
|
data: &$request_type,
|
||||||
) -> miette::Result<(), crate::error::TeslatteError> {
|
) -> miette::Result<crate::Data<crate::PostResponse>, crate::error::TeslatteError> {
|
||||||
let url = format!($url, arg);
|
let url = format!($url, arg);
|
||||||
let url = format!("{}{}", crate::API_URL, url);
|
let url = format!("{}{}", crate::API_URL, url);
|
||||||
self.post(&url, data).await
|
self.post(&url, data).await
|
||||||
|
@ -296,7 +298,7 @@ macro_rules! post_arg_empty {
|
||||||
pub async fn $name(
|
pub async fn $name(
|
||||||
&self,
|
&self,
|
||||||
arg: &$arg_type,
|
arg: &$arg_type,
|
||||||
) -> miette::Result<(), crate::error::TeslatteError> {
|
) -> miette::Result<crate::Data<crate::PostResponse>, crate::error::TeslatteError> {
|
||||||
let url = format!($url, arg);
|
let url = format!($url, arg);
|
||||||
let url = format!("{}{}", crate::API_URL, url);
|
let url = format!("{}{}", crate::API_URL, url);
|
||||||
self.post(&url, &Empty {}).await
|
self.post(&url, &Empty {}).await
|
||||||
|
|
|
@ -106,13 +106,13 @@ async fn main() -> miette::Result<()> {
|
||||||
let api = Api::new(access_token, refresh_token);
|
let api = Api::new(access_token, refresh_token);
|
||||||
match api_args.command {
|
match api_args.command {
|
||||||
ApiCommand::Vehicles => {
|
ApiCommand::Vehicles => {
|
||||||
print_json(api.vehicles().await?);
|
print_json(api.vehicles().await);
|
||||||
}
|
}
|
||||||
ApiCommand::Vehicle(v) => {
|
ApiCommand::Vehicle(v) => {
|
||||||
v.run(&api).await?;
|
v.run(&api).await?;
|
||||||
}
|
}
|
||||||
ApiCommand::EnergySites => {
|
ApiCommand::EnergySites => {
|
||||||
print_json(api.energy_sites().await?);
|
print_json(api.energy_sites().await);
|
||||||
}
|
}
|
||||||
ApiCommand::EnergySite(e) => {
|
ApiCommand::EnergySite(e) => {
|
||||||
e.run(&api).await?;
|
e.run(&api).await?;
|
||||||
|
|
|
@ -38,7 +38,7 @@ pub struct VehicleData {
|
||||||
/// gak: This was null for me, assuming String.
|
/// gak: This was null for me, assuming String.
|
||||||
pub backseat_token_updated_at: Option<String>,
|
pub backseat_token_updated_at: Option<String>,
|
||||||
|
|
||||||
/// Some of these have been null for me, so making them all Option.
|
/// gak: Some of these have been null for me, so making them all Option.
|
||||||
pub charge_state: Option<ChargeState>,
|
pub charge_state: Option<ChargeState>,
|
||||||
pub climate_state: Option<ClimateState>,
|
pub climate_state: Option<ClimateState>,
|
||||||
pub drive_state: Option<DriveState>,
|
pub drive_state: Option<DriveState>,
|
||||||
|
|
Loading…
Reference in a new issue