use anyhow::Context; use chrono::DateTime; use serde::{Deserialize, Serialize}; #[derive(Default)] pub struct CarState { pub charge_state: Option, pub location_data: Option, pub climate_state: Option, } #[derive(Clone, Copy, Serialize, Deserialize, Debug)] pub struct ClimateState { pub inside_temp: f64, } impl TryFrom for ClimateState { type Error = anyhow::Error; fn try_from(value: teslatte::vehicles::ClimateState) -> Result { Ok(Self { inside_temp: value .inside_temp .context("no temperature in climate data")?, }) } } #[derive(Clone, Copy, Serialize, Deserialize, Debug)] pub struct ChargeState { pub battery_level: i64, pub battery_range: f64, pub charge_amps: i64, pub charge_rate: f64, pub charge_current_request: i64, pub charge_current_request_max: i64, pub charge_enable_request: bool, pub charge_limit_soc: i64, } impl ChargeState { #[allow(unused)] pub fn range_km(&self) -> f64 { self.battery_range * 1.60934 } } impl From for ChargeState { fn from(value: teslatte::vehicles::ChargeState) -> Self { ChargeState { battery_level: value.battery_level, battery_range: value.battery_range, charge_amps: value.charge_amps, charge_rate: value.charge_rate, charge_current_request: value.charge_current_request, charge_current_request_max: value.charge_current_request_max, charge_enable_request: value.charge_enable_request, charge_limit_soc: value.charge_limit_soc, } } } #[derive(Clone, Copy, Serialize, Deserialize, Debug)] pub struct LocationData { pub coords: Coords, pub gps_as_of: DateTime, } impl TryFrom for LocationData { type Error = anyhow::Error; fn try_from(value: teslatte::vehicles::DriveState) -> Result { let gps_as_of = chrono::DateTime::from_timestamp(value.gps_as_of.context("no gps timestamp!")?, 0) .context("could not process timestamp!")?; let coords = Coords { latitude: value.latitude.context("no longitude provided!")?, longitude: value.longitude.context("no latitude provided!")?, }; Ok(Self { coords, gps_as_of }) } } #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct Coords { pub latitude: f64, pub longitude: f64, } const COORD_PRECISION: f64 = 0.001; impl Coords { pub fn overlaps(&self, other: &Coords) -> bool { (self.latitude - other.latitude).abs() < COORD_PRECISION && (self.longitude - other.longitude).abs() < COORD_PRECISION } }