ditch anyhow

This commit is contained in:
Alex Janka 2024-01-12 08:47:21 +11:00
parent 904513b71a
commit 7dd4cc43b1
6 changed files with 54 additions and 43 deletions

7
Cargo.lock generated
View file

@ -101,12 +101,6 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "anyhow"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
[[package]]
name = "arc-swap"
version = "1.6.0"
@ -2264,7 +2258,6 @@ dependencies = [
name = "tesla-charge-controller"
version = "0.1.17-prerelease"
dependencies = [
"anyhow",
"async-channel",
"chrono",
"clap",

View file

@ -20,7 +20,6 @@ tokio = { version = "1.35.1", features = ["full"] }
teslatte = { path = "./vendored/teslatte" }
thiserror = "1.0"
rocket = { version = "0.5", features = ["json"] }
anyhow = "1.0"
include_dir = "0.7"
chrono = "0.4"
async-channel = "2.1"

View file

@ -1,4 +1,3 @@
use anyhow::{Context, Result};
use metrics::{describe_gauge, gauge, Gauge, Unit};
use serde::{Deserialize, Serialize};
use std::{
@ -93,7 +92,7 @@ impl TeslaInterface {
_ => None,
})
.next()
.context("No vehicles attached to account!")?;
.ok_or(AuthLoadError::NoVehicles)?;
let metrics = Metrics::new();

View file

@ -27,8 +27,8 @@ pub enum AuthLoadError {
Teslatte(#[from] teslatte::error::TeslatteError),
#[error("save error")]
Save(#[from] SaveError),
#[error("other error")]
Anyhow(#[from] anyhow::Error),
#[error("no vehicles")]
NoVehicles,
}
impl AuthLoadError {
@ -38,7 +38,7 @@ impl AuthLoadError {
AuthLoadError::StdIo(e) => format!("Error reading access token from disk: {e:?}"),
AuthLoadError::RonSpanned(e) => format!("Error deserialising access token: {e:?}"),
AuthLoadError::Save(e) => e.error_string(),
AuthLoadError::Anyhow(e) => e.to_string(),
AuthLoadError::NoVehicles => String::from("No vehicles attached to account"),
}
}
}
@ -54,3 +54,17 @@ pub enum RequestError {
#[error("save error")]
Save(#[from] SaveError),
}
#[derive(Error, Debug)]
pub enum PliError {
#[error("read error")]
ReadError(u8),
}
#[derive(Error, Debug)]
pub enum TeslaStateParseError {
#[error("No associated value")]
NoValue,
#[error("Invalid timestamp")]
InvalidTimestamp,
}

View file

@ -4,12 +4,13 @@ use std::{
time::Duration,
};
use anyhow::Context;
use metrics::{describe_gauge, gauge, Gauge};
use serde::{Deserialize, Serialize};
use serialport::SerialPort;
use termcolor::WriteColor;
use crate::errors::PliError;
pub struct Pli {
pub state: Arc<RwLock<PlState>>,
port: Box<dyn SerialPort>,
@ -122,7 +123,7 @@ pub enum PliRequest {
}
impl Pli {
pub fn new(serial_port: String, baud_rate: u32) -> anyhow::Result<Self> {
pub fn new(serial_port: String, baud_rate: u32) -> Result<Self, serialport::Error> {
let port = serialport::new(serial_port, baud_rate)
.timeout(Duration::from_millis(250))
.open()?;
@ -151,17 +152,20 @@ impl Pli {
}
pub fn refresh(&mut self) {
if let Ok(new_state) = self.read_state() {
self.voltage_gauge.set(new_state.battery_voltage);
self.target_voltage_gauge.set(new_state.target_voltage);
self.duty_cycle.set(new_state.duty_cycle);
self.internal_charge_current
.set(new_state.internal_charge_current);
self.internal_load_current
.set(new_state.internal_load_current);
self.regulator_gauges.set(&new_state.regulator_state);
match self.read_state() {
Ok(new_state) => {
self.voltage_gauge.set(new_state.battery_voltage);
self.target_voltage_gauge.set(new_state.target_voltage);
self.duty_cycle.set(new_state.duty_cycle);
self.internal_charge_current
.set(new_state.internal_charge_current);
self.internal_load_current
.set(new_state.internal_load_current);
self.regulator_gauges.set(&new_state.regulator_state);
*self.state.write().expect("PLI state handler panicked!!") = new_state;
*self.state.write().expect("PLI state handler panicked!!") = new_state;
}
Err(e) => log::error!("State read error: {e:#?}"),
}
}
@ -185,7 +189,7 @@ impl Pli {
}
}
fn read_state(&mut self) -> anyhow::Result<PlState> {
fn read_state(&mut self) -> Result<PlState, PliError> {
Ok(PlState {
battery_voltage: (self.read_ram(PlRamAddress::Batv)? as f64) * (4. / 10.),
target_voltage: (self.read_ram(PlRamAddress::Vreg)? as f64) * (4. / 10.),
@ -211,14 +215,17 @@ impl Pli {
buf
}
fn read_ram<T>(&mut self, address: T) -> anyhow::Result<u8>
fn read_ram<T>(&mut self, address: T) -> Result<u8, PliError>
where
T: Into<u8>,
{
self.send_command(command(20, address.into(), 0));
let buf: [u8; 2] = self.receive();
if buf[0] == 200 { Some(buf[1]) } else { None }
.context(format!("Error from PLI: {}", buf[0]))
if buf[0] == 200 {
Ok(buf[1])
} else {
Err(PliError::ReadError(buf[0]))
}
}
}

View file

@ -1,7 +1,8 @@
use anyhow::Context;
use chrono::DateTime;
use serde::{Deserialize, Serialize};
use crate::errors::TeslaStateParseError;
#[derive(Default)]
pub struct CarState {
pub charge_state: Option<ChargeState>,
@ -17,17 +18,13 @@ pub struct ClimateState {
}
impl TryFrom<teslatte::vehicles::ClimateState> for ClimateState {
type Error = anyhow::Error;
type Error = TeslaStateParseError;
fn try_from(value: teslatte::vehicles::ClimateState) -> Result<Self, Self::Error> {
Ok(Self {
inside_temp: value
.inside_temp
.context("no inside temperature in climate data")?,
inside_temp: value.inside_temp.ok_or(TeslaStateParseError::NoValue)?,
outside_temp: value
.outside_temp
.context("no outside temperature in climate data")?,
outside_temp: value.outside_temp.ok_or(TeslaStateParseError::NoValue)?,
battery_heater: value.battery_heater,
})
}
@ -74,15 +71,17 @@ pub struct LocationData {
}
impl TryFrom<teslatte::vehicles::DriveState> for LocationData {
type Error = anyhow::Error;
type Error = TeslaStateParseError;
fn try_from(value: teslatte::vehicles::DriveState) -> Result<Self, Self::Error> {
let gps_as_of =
chrono::DateTime::from_timestamp(value.gps_as_of.context("no gps timestamp!")?, 0)
.context("could not process timestamp!")?;
let gps_as_of = chrono::DateTime::from_timestamp(
value.gps_as_of.ok_or(TeslaStateParseError::NoValue)?,
0,
)
.ok_or(TeslaStateParseError::InvalidTimestamp)?;
let coords = Coords {
latitude: value.latitude.context("no longitude provided!")?,
longitude: value.longitude.context("no latitude provided!")?,
latitude: value.latitude.ok_or(TeslaStateParseError::NoValue)?,
longitude: value.longitude.ok_or(TeslaStateParseError::NoValue)?,
};
Ok(Self { coords, gps_as_of })
}