2024-01-08 12:00:09 +11:00
|
|
|
use anyhow::Context;
|
|
|
|
use chrono::DateTime;
|
2024-01-07 10:08:16 +11:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
2024-01-08 12:00:09 +11:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct CarState {
|
|
|
|
pub charge_state: Option<ChargeState>,
|
|
|
|
pub location_data: Option<LocationData>,
|
2024-01-09 11:11:16 +11:00
|
|
|
pub climate_state: Option<ClimateState>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
|
|
|
pub struct ClimateState {
|
|
|
|
pub inside_temp: f64,
|
2024-01-09 12:06:18 +11:00
|
|
|
pub outside_temp: f64,
|
|
|
|
pub battery_heater: bool,
|
2024-01-09 11:11:16 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<teslatte::vehicles::ClimateState> for ClimateState {
|
|
|
|
type Error = anyhow::Error;
|
|
|
|
|
|
|
|
fn try_from(value: teslatte::vehicles::ClimateState) -> Result<Self, Self::Error> {
|
|
|
|
Ok(Self {
|
|
|
|
inside_temp: value
|
|
|
|
.inside_temp
|
2024-01-09 12:06:18 +11:00
|
|
|
.context("no inside temperature in climate data")?,
|
|
|
|
|
|
|
|
outside_temp: value
|
|
|
|
.outside_temp
|
|
|
|
.context("no outside temperature in climate data")?,
|
|
|
|
battery_heater: value.battery_heater,
|
2024-01-09 11:11:16 +11:00
|
|
|
})
|
|
|
|
}
|
2024-01-08 12:00:09 +11:00
|
|
|
}
|
|
|
|
|
2024-01-07 10:08:16 +11:00
|
|
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
|
|
|
pub struct ChargeState {
|
|
|
|
pub battery_level: i64,
|
|
|
|
pub battery_range: f64,
|
|
|
|
pub charge_amps: i64,
|
2024-01-07 10:33:32 +11:00
|
|
|
pub charge_rate: f64,
|
2024-01-07 10:08:16 +11:00
|
|
|
pub charge_current_request: i64,
|
|
|
|
pub charge_current_request_max: i64,
|
|
|
|
pub charge_enable_request: bool,
|
2024-01-07 10:33:32 +11:00
|
|
|
pub charge_limit_soc: i64,
|
2024-01-07 10:08:16 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ChargeState {
|
|
|
|
#[allow(unused)]
|
|
|
|
pub fn range_km(&self) -> f64 {
|
|
|
|
self.battery_range * 1.60934
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<teslatte::vehicles::ChargeState> 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,
|
2024-01-07 10:33:32 +11:00
|
|
|
charge_rate: value.charge_rate,
|
2024-01-07 10:08:16 +11:00
|
|
|
charge_current_request: value.charge_current_request,
|
|
|
|
charge_current_request_max: value.charge_current_request_max,
|
|
|
|
charge_enable_request: value.charge_enable_request,
|
2024-01-07 10:33:32 +11:00
|
|
|
charge_limit_soc: value.charge_limit_soc,
|
2024-01-07 10:08:16 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-01-08 12:00:09 +11:00
|
|
|
|
|
|
|
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
|
|
|
pub struct LocationData {
|
|
|
|
pub coords: Coords,
|
|
|
|
pub gps_as_of: DateTime<chrono::Utc>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<teslatte::vehicles::DriveState> for LocationData {
|
|
|
|
type Error = anyhow::Error;
|
|
|
|
|
|
|
|
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 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
|
|
|
|
}
|
|
|
|
}
|