Explicit login, token save, ergonomics
This commit is contained in:
parent
14164037d3
commit
d490970ab0
188
src/main.rs
188
src/main.rs
@ -1,12 +1,12 @@
|
||||
use clap::ValueEnum;
|
||||
use clap::{Parser, Subcommand};
|
||||
use anyhow::Result;
|
||||
use easee::api;
|
||||
use anyhow::{Context, Result};
|
||||
use easee::api::ChargingSession;
|
||||
use easee::stream;
|
||||
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Debug,Clone,ValueEnum)]
|
||||
#[derive(Debug,Clone,Copy,ValueEnum)]
|
||||
enum Command {
|
||||
Start,
|
||||
Stop,
|
||||
@ -14,93 +14,133 @@ enum Command {
|
||||
Resume,
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Copy,ValueEnum)]
|
||||
enum Session {
|
||||
Ongoing,
|
||||
Latest
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone,Subcommand)]
|
||||
enum Mode {
|
||||
Status { id: Option<String> },
|
||||
Ongoing,
|
||||
Latest,
|
||||
Login,
|
||||
Status,
|
||||
Session {
|
||||
#[arg(default_value = "ongoing")]
|
||||
session: Session
|
||||
},
|
||||
Charge { command: Command },
|
||||
Stream,
|
||||
Command { id: String, command: Command }
|
||||
}
|
||||
|
||||
#[derive(Debug,Parser)]
|
||||
struct CLI {
|
||||
#[arg(short,long,env)]
|
||||
username: String,
|
||||
#[arg(short,long,env)]
|
||||
password: String,
|
||||
#[arg(short,long)]
|
||||
debug: bool,
|
||||
|
||||
#[arg(short,long)]
|
||||
charger_id: Vec<String>,
|
||||
|
||||
#[command(subcommand)]
|
||||
mode: Mode,
|
||||
}
|
||||
|
||||
const SAVED_TOKEN_PATH: &str = ".easee_token";
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
||||
tracing::subscriber::set_global_default(tracing_subscriber::FmtSubscriber::new())
|
||||
.expect("Tracing subscriber failed");
|
||||
|
||||
let args = CLI::parse();
|
||||
let mut ctx = api::Context::from_login(&args.username, &args.password)?;
|
||||
|
||||
info!("Logged in");
|
||||
|
||||
let sites = ctx.sites()?;
|
||||
let chargers = ctx.chargers()?;
|
||||
info!("{} sites and {} chargers available", sites.len(), chargers.len());
|
||||
|
||||
match args.mode {
|
||||
Mode::Status { id } => {
|
||||
for c in &chargers {
|
||||
if id.as_deref().map(|id| id == &c.id).unwrap_or(true) {
|
||||
println!("{}: {:?}", c.id, c.state(&mut ctx));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
Mode::Ongoing => {
|
||||
for c in &chargers {
|
||||
println!("{}: {:?}", c.id, c.ongoing_session(&mut ctx));
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
Mode::Latest => {
|
||||
for c in &chargers {
|
||||
println!("{:?}", c.latest_session(&mut ctx));
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
Mode::Stream => {
|
||||
let mut stream = stream::Stream::open(&mut ctx)?;
|
||||
for c in &chargers {
|
||||
stream.subscribe(&c.id)?;
|
||||
}
|
||||
|
||||
let mut stream = easee::signalr::Stream::from_ws(stream);
|
||||
loop {
|
||||
println!("{:?}", stream.recv()?);
|
||||
}
|
||||
},
|
||||
Mode::Command { id, command } => {
|
||||
|
||||
for c in &chargers {
|
||||
if c.id == id {
|
||||
match command {
|
||||
Command::Start => c.start(&mut ctx)?,
|
||||
Command::Stop => c.stop(&mut ctx)?,
|
||||
Command::Pause => c.pause(&mut ctx)?,
|
||||
Command::Resume => c.resume(&mut ctx)?,
|
||||
}
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
eprintln!("Charger not found.");
|
||||
Ok(())
|
||||
|
||||
},
|
||||
|
||||
|
||||
if args.debug {
|
||||
tracing::subscriber::set_global_default(tracing_subscriber::FmtSubscriber::new())
|
||||
.expect("Tracing subscriber failed");
|
||||
}
|
||||
|
||||
if let Mode::Login = args.mode {
|
||||
use std::io::Write;
|
||||
let stdin = std::io::stdin();
|
||||
let mut stderr = std::io::stderr();
|
||||
|
||||
let mut username = String::new();
|
||||
let mut password = String::new();
|
||||
|
||||
write!(stderr, "Username: ")?;
|
||||
stdin.read_line(&mut username)?;
|
||||
write!(stderr, "Password: ")?;
|
||||
stdin.read_line(&mut password)?;
|
||||
|
||||
let username = username.trim();
|
||||
let password = password.trim();
|
||||
|
||||
let ctx = easee::api::Context::from_login(&username, &password)?;
|
||||
eprintln!("Login successful.");
|
||||
|
||||
std::fs::write(SAVED_TOKEN_PATH, ctx.save().as_bytes())?;
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let saved = std::fs::read_to_string(SAVED_TOKEN_PATH)
|
||||
.context("Cannot read saved token (did you log in ?)")?;
|
||||
let mut ctx = easee::api::Context::from_saved(&saved)?;
|
||||
|
||||
let chargers;
|
||||
if args.charger_id.is_empty() {
|
||||
chargers = ctx.chargers()?;
|
||||
info!("{} chargers available.", chargers.len());
|
||||
} else {
|
||||
chargers = args.charger_id.iter()
|
||||
.map(|id| ctx.charger(&id))
|
||||
.collect::<Result<_,_>>()?;
|
||||
}
|
||||
|
||||
if let Mode::Stream = args.mode {
|
||||
let mut stream = stream::Stream::open(&mut ctx)?;
|
||||
for c in &chargers {
|
||||
stream.subscribe(&c.id)?;
|
||||
}
|
||||
|
||||
let mut stream = easee::signalr::Stream::from_ws(stream);
|
||||
loop {
|
||||
println!("{:?}", stream.recv()?);
|
||||
}
|
||||
}
|
||||
|
||||
for c in &chargers {
|
||||
match args.mode {
|
||||
Mode::Status => {
|
||||
println!("{}: {:?}", c.id, c.state(&mut ctx));
|
||||
},
|
||||
Mode::Session { session: Session::Ongoing }=> {
|
||||
show_session(&c.ongoing_session(&mut ctx)?);
|
||||
},
|
||||
Mode::Session { session: Session::Latest } => {
|
||||
show_session(&c.latest_session(&mut ctx)?);
|
||||
},
|
||||
Mode::Charge { command } => {
|
||||
match command {
|
||||
Command::Start => c.start(&mut ctx)?,
|
||||
Command::Stop => c.stop(&mut ctx)?,
|
||||
Command::Pause => c.pause(&mut ctx)?,
|
||||
Command::Resume => c.resume(&mut ctx)?,
|
||||
}
|
||||
},
|
||||
_other => {
|
||||
unreachable!("Stream was already ruled out above")
|
||||
},
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
fn show_session(s: &Option<ChargingSession>) {
|
||||
let Some(s) = s.as_ref() else { return };
|
||||
|
||||
let duration = std::time::Duration::from_secs(
|
||||
s.charge_duration_in_seconds.unwrap_or(0) as u64
|
||||
);
|
||||
|
||||
println!("{}\t{}\t{}kWh",
|
||||
s.charger_id.as_deref().unwrap_or("<none>"),
|
||||
humantime::format_duration(duration),
|
||||
s.session_energy,
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user