use chrono::DateTime; use serde::{Deserialize, Serialize}; use crate::errors::TeslaStateParseError; #[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, pub outside_temp: f64, pub battery_heater: bool, } impl TryFrom for ClimateState { type Error = TeslaStateParseError; fn try_from(value: teslatte::vehicles::ClimateState) -> Result { Ok(Self { inside_temp: value.inside_temp.ok_or(TeslaStateParseError::NoValue)?, outside_temp: value.outside_temp.ok_or(TeslaStateParseError::NoValue)?, battery_heater: value.battery_heater, }) } } #[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 = TeslaStateParseError; fn try_from(value: teslatte::vehicles::DriveState) -> Result { 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.ok_or(TeslaStateParseError::NoValue)?, longitude: value.longitude.ok_or(TeslaStateParseError::NoValue)?, }; 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 } }