Compare commits
32 commits
cf30a7d1bc
...
ef26ce4697
Author | SHA1 | Date | |
---|---|---|---|
Alex Janka | ef26ce4697 | ||
Alex Janka | fd1794744b | ||
Alex Janka | 3add4893f9 | ||
Alex Janka | b13c40429f | ||
Alex Janka | 64aa35a969 | ||
Alex Janka | a2bc59fb34 | ||
Alex Janka | 9ecf21554e | ||
Alex Janka | 677d959e6d | ||
Alex Janka | 78d347f38e | ||
Alex Janka | 3123cad1a5 | ||
13f4be3478 | |||
e326d17c14 | |||
6f7fb72943 | |||
62b3343b21 | |||
19ac4b485d | |||
1e6c1d5ff3 | |||
fcc9e63930 | |||
afd833f13f | |||
6723c0ad02 | |||
8b5141376e | |||
0de5ee26b9 | |||
906ce9cf04 | |||
b7e2f94884 | |||
63015deb1b | |||
325b899504 | |||
a16ca64151 | |||
4ba1dd2c33 | |||
796c09c17a | |||
c8b45d5c3e | |||
280f5751cc | |||
c2b12df27b | |||
85e3728a1d |
46
CHANGELOG.md
46
CHANGELOG.md
|
@ -5,10 +5,46 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.1.15] - 2023-04-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Forgot a `total_pack_energy`. (#22)
|
||||
|
||||
## [0.1.14] - 2023-04-12
|
||||
|
||||
### Changed
|
||||
|
||||
- `energy_left` and `total_pack_energy` are gone from the API. (#22)
|
||||
- Don't rely on serde untagged to determine the product type, as any missing
|
||||
fields will give an unspecified error. Instead directly check known fields
|
||||
that will probably not be removed. https://github.com/serde-rs/serde/pull/2376
|
||||
|
||||
## [0.1.13] - 2023-01-24
|
||||
|
||||
### Changed
|
||||
|
||||
- Vehicles list is gone from the API. Use `products` instead. (#13)
|
||||
|
||||
## [0.1.12] - 2023-01-20
|
||||
|
||||
### Changed
|
||||
|
||||
- PowerwallData new fields:
|
||||
- powerwall_onboarding_settings_set
|
||||
- storm_mode_enabled
|
||||
- features
|
||||
- warp_site_number
|
||||
- go_off_grid_test_banner_enabled
|
||||
- powerwall_tesla_electric_interested_in
|
||||
- vpp_tour_enabled
|
||||
- Components market_type is now Option<String>
|
||||
- LiveWallConnector wall_connector_power is now f32
|
||||
|
||||
## [0.1.11] - 2023-11-11
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
- `vehicle_data` now accepts `GetVehicleData` instead of `VehicleId`. (See [6facc27](https://github.com/gak/teslatte/commit/6facc27d8b408d35b98b4c6c0ad3e5df82328d2c))
|
||||
|
||||
## [0.1.10] - 2023-11-11
|
||||
|
@ -16,17 +52,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Changed
|
||||
|
||||
- API changes for "api_version 67"
|
||||
|
||||
- VehicleData new fields:
|
||||
|
||||
- cached_data
|
||||
- command_signing
|
||||
- release_notes_supported
|
||||
|
||||
- ClimateState new fields:
|
||||
|
||||
- auto_steering_wheel_heat
|
||||
- cop_activation_temperature,
|
||||
- steering_wheel_heat_level
|
||||
|
||||
- DriveState now Optional:
|
||||
|
||||
- gps_as_of
|
||||
- heading
|
||||
- latitude
|
||||
|
@ -37,16 +77,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- native_type
|
||||
|
||||
- DriveState new fields:
|
||||
|
||||
- active_route_traffic_minutes_delay
|
||||
|
||||
- GuiSettings new field:
|
||||
|
||||
- gui_tirepressure_units
|
||||
|
||||
- VehicleConfig new fields:
|
||||
|
||||
- cop_user_set_temp_supported
|
||||
- webcam_selfie_supported
|
||||
|
||||
- VehicleState new fields:
|
||||
|
||||
- media_info: MediaInfo
|
||||
- tpms_hard_warning_fl
|
||||
- tpms_hard_warning_fr
|
||||
|
|
28
Cargo.toml
28
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "teslatte"
|
||||
version = "0.1.11"
|
||||
version = "0.1.15"
|
||||
description = "A command line tool and Rust crate for querying the Tesla API."
|
||||
edition = "2021"
|
||||
rust-version = "1.75.0"
|
||||
|
@ -20,25 +20,25 @@ path = "src/main.rs"
|
|||
required-features = ["cli"]
|
||||
|
||||
[dependencies]
|
||||
miette = { version = "5.10.0", features = ["fancy"] }
|
||||
thiserror = "1.0.50"
|
||||
tokio = { version = "1.33.0", features = ["full"] }
|
||||
miette = { version = "7.2.0", features = ["fancy"] }
|
||||
thiserror = "1.0.56"
|
||||
tokio = { version = "1.35.1", features = ["full"] }
|
||||
tracing = "0.1.40"
|
||||
reqwest = { version = "0.11.22", features = ["rustls-tls", "cookies", "json"] }
|
||||
url = "2.4.1"
|
||||
serde = { version = "1.0.189", features = ["derive"] }
|
||||
serde_json = "1.0.107"
|
||||
rustls = "0.22.1"
|
||||
reqwest = { version = "0.12.3", features = ["rustls-tls", "cookies", "json"] }
|
||||
url = "2.5.0"
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
serde_json = "1.0.111"
|
||||
rustls = "0.23.0"
|
||||
rand = "0.8.5"
|
||||
chrono = { version = "0.4.31", features = ["serde"] }
|
||||
strum = { version = "0.25.0", features = ["derive"] }
|
||||
strum = { version = "0.26.1", features = ["derive"] }
|
||||
urlencoding = "2.1.3"
|
||||
derive_more = "0.99.17"
|
||||
pkce = "0.2.0"
|
||||
|
||||
clap = { version = "4.4.6", features = ["derive", "env"], optional = true }
|
||||
tracing-subscriber = { version = "0.3.17", optional = true }
|
||||
colored_json = { version = "4.0.0", optional = true }
|
||||
clap = { version = "4.4.18", features = ["derive", "env"], optional = true }
|
||||
tracing-subscriber = { version = "0.3.18", optional = true }
|
||||
colored_json = { version = "5.0.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
test-log = { version = "0.2.13", default-features = false, features = ["trace"] }
|
||||
test-log = { version = "0.2.14", default-features = false, features = ["trace"] }
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use std::env;
|
||||
use teslatte::auth::AccessToken;
|
||||
use teslatte::products::Product;
|
||||
use teslatte::vehicles::GetVehicleData;
|
||||
use teslatte::{OwnerApi, VehicleApi};
|
||||
use teslatte::OwnerApi;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -17,19 +16,8 @@ async fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
let vehicles = api.vehicles().await.unwrap();
|
||||
dbg!(&*vehicles);
|
||||
|
||||
if !vehicles.is_empty() {
|
||||
let get_vehicle_data = GetVehicleData::new(vehicles[0].id.clone());
|
||||
let vehicle_data = api.vehicle_data(&get_vehicle_data).await.unwrap();
|
||||
dbg!(&vehicle_data);
|
||||
} else {
|
||||
println!("No vehicles found!");
|
||||
}
|
||||
|
||||
let products = api.products().await.unwrap();
|
||||
dbg!(&*products);
|
||||
dbg!(&products);
|
||||
|
||||
if !products.is_empty() {
|
||||
for product in &*products {
|
||||
|
|
7
justfile
7
justfile
|
@ -7,9 +7,8 @@ no_token_test:
|
|||
|
||||
# Require an access token from "cli.json". Use `just auth` to generate.
|
||||
token_tests:
|
||||
cargo run -- api vehicles
|
||||
cargo run --no-default-features --features cli -- api vehicles
|
||||
cargo run -- api products
|
||||
cargo run --no-default-features --features cli -- api products
|
||||
|
||||
publish version:
|
||||
git diff-index --quiet HEAD
|
||||
|
@ -30,3 +29,7 @@ auth:
|
|||
|
||||
audit:
|
||||
cargo audit
|
||||
|
||||
update:
|
||||
cargo update && cargo upgrade
|
||||
cd tesla_api_coverage && cargo update && cargo upgrade
|
||||
|
|
|
@ -18,7 +18,6 @@ pub struct SiteStatus {
|
|||
pub battery_power: i64,
|
||||
pub battery_type: String,
|
||||
pub breaker_alert_enabled: bool,
|
||||
pub energy_left: f64,
|
||||
pub gateway_id: String,
|
||||
pub percentage_charged: f64,
|
||||
pub powerwall_onboarding_settings_set: bool,
|
||||
|
@ -29,14 +28,12 @@ pub struct SiteStatus {
|
|||
pub site_name: String,
|
||||
pub storm_mode_enabled: bool,
|
||||
pub sync_grid_alert_enabled: bool,
|
||||
pub total_pack_energy: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct LiveStatus {
|
||||
pub backup_capable: bool,
|
||||
pub battery_power: i64,
|
||||
pub energy_left: f64,
|
||||
pub generator_power: i64,
|
||||
pub grid_power: i64,
|
||||
pub grid_services_active: bool,
|
||||
|
@ -48,7 +45,6 @@ pub struct LiveStatus {
|
|||
pub solar_power: i64,
|
||||
pub storm_mode_active: bool,
|
||||
pub timestamp: String,
|
||||
pub total_pack_energy: i64,
|
||||
pub wall_connectors: Vec<LiveWallConnector>,
|
||||
}
|
||||
|
||||
|
@ -69,7 +65,7 @@ pub struct LiveWallConnector {
|
|||
/// 2: not plugged in
|
||||
/// 4: plugged in (not charging)
|
||||
pub wall_connector_state: i64,
|
||||
pub wall_connector_power: i64,
|
||||
pub wall_connector_power: f32,
|
||||
pub wall_connector_fault_state: i64,
|
||||
}
|
||||
|
||||
|
@ -311,7 +307,7 @@ mod tests {
|
|||
vin: Some("1234".to_string()),
|
||||
din: "5432".to_string(),
|
||||
wall_connector_state: 4,
|
||||
wall_connector_power: 0,
|
||||
wall_connector_power: 0.,
|
||||
wall_connector_fault_state: 2,
|
||||
}
|
||||
);
|
||||
|
@ -336,7 +332,7 @@ mod tests {
|
|||
vin: None,
|
||||
din: "1234".to_string(),
|
||||
wall_connector_state: 2,
|
||||
wall_connector_power: 0,
|
||||
wall_connector_power: 0.,
|
||||
wall_connector_fault_state: 2,
|
||||
}
|
||||
);
|
||||
|
|
|
@ -32,7 +32,6 @@ const API_URL: &str = if cfg!(debug_assertions) {
|
|||
};
|
||||
|
||||
pub trait VehicleApi {
|
||||
async fn vehicles(&self) -> Result<Vec<Vehicle>, TeslatteError>;
|
||||
async fn vehicle_data(
|
||||
&self,
|
||||
get_vehicle_data: &GetVehicleData,
|
||||
|
@ -157,8 +156,6 @@ pub trait FleetVehicleApi {
|
|||
async fn remote_start_drive(&self, vin: &str) -> Result<PostResponse, TeslatteError>;
|
||||
}
|
||||
|
||||
trait EnergySitesApi {}
|
||||
|
||||
trait ApiValues {
|
||||
fn format(&self, url: &str) -> String;
|
||||
}
|
||||
|
@ -502,6 +499,7 @@ struct ResponseError {
|
|||
struct Empty {}
|
||||
|
||||
/// GET /api/1/[url]
|
||||
#[allow(unused_macros)]
|
||||
macro_rules! get {
|
||||
($name:ident, $return_type:ty, $url:expr) => {
|
||||
async fn $name(&self) -> Result<$return_type, crate::error::TeslatteError> {
|
||||
|
@ -512,6 +510,7 @@ macro_rules! get {
|
|||
}
|
||||
};
|
||||
}
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use get;
|
||||
|
||||
/// Same as get, but public.
|
||||
|
|
|
@ -4,7 +4,7 @@ use teslatte::auth::{AccessToken, RefreshToken};
|
|||
use teslatte::cli::energy::EnergySiteArgs;
|
||||
use teslatte::cli::powerwall::PowerwallArgs;
|
||||
use teslatte::cli::vehicle::VehicleArgs;
|
||||
use teslatte::{OwnerApi, PrintResponses, VehicleApi};
|
||||
use teslatte::{OwnerApi, PrintResponses};
|
||||
|
||||
/// Teslatte
|
||||
///
|
||||
|
@ -106,7 +106,7 @@ async fn main() -> miette::Result<()> {
|
|||
api.print_responses = PrintResponses::Pretty;
|
||||
match api_args.command {
|
||||
ApiCommand::Vehicles => {
|
||||
api.vehicles().await?;
|
||||
panic!("Tesla API has changed. This command is no longer works with the Owners API.");
|
||||
}
|
||||
ApiCommand::Vehicle(v) => {
|
||||
v.run(&api).await?;
|
||||
|
|
123
src/products.rs
123
src/products.rs
|
@ -4,7 +4,8 @@ use crate::powerwall::PowerwallId;
|
|||
use crate::vehicles::VehicleData;
|
||||
use crate::{pub_get, FleetApi, OwnerApi};
|
||||
use derive_more::Display;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[rustfmt::skip]
|
||||
|
@ -33,14 +34,44 @@ impl FromStr for EnergySiteId {
|
|||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GatewayId(String);
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Product {
|
||||
Vehicle(Box<VehicleData>),
|
||||
Solar(Box<SolarData>),
|
||||
Powerwall(Box<PowerwallData>),
|
||||
}
|
||||
|
||||
fn deserialize_product<'de, D>(deserializer: D) -> Result<Product, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let v = Value::deserialize(deserializer)?;
|
||||
|
||||
if v.get("vehicle_id").is_some() {
|
||||
let vehicle_data = VehicleData::deserialize(v).map_err(serde::de::Error::custom)?;
|
||||
Ok(Product::Vehicle(Box::new(vehicle_data)))
|
||||
} else if v.get("solar_type").is_some() {
|
||||
let solar_data = SolarData::deserialize(v).map_err(serde::de::Error::custom)?;
|
||||
Ok(Product::Solar(Box::new(solar_data)))
|
||||
} else if v.get("battery_type").is_some() {
|
||||
let powerwall_data = PowerwallData::deserialize(v).map_err(serde::de::Error::custom)?;
|
||||
Ok(Product::Powerwall(Box::new(powerwall_data)))
|
||||
} else {
|
||||
Err(serde::de::Error::custom(
|
||||
"No valid key found to determine the product type",
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Product {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Product, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
deserialize_product(deserializer)
|
||||
}
|
||||
}
|
||||
|
||||
/// This is assumed from https://tesla-api.timdorr.com/api-basics/products
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct SolarData {
|
||||
|
@ -66,14 +97,25 @@ pub struct PowerwallData {
|
|||
pub id: PowerwallId,
|
||||
pub gateway_id: GatewayId,
|
||||
pub asset_site_id: String,
|
||||
pub energy_left: f64,
|
||||
pub total_pack_energy: i64,
|
||||
pub percentage_charged: f64,
|
||||
pub backup_capable: bool,
|
||||
pub battery_power: i64,
|
||||
pub sync_grid_alert_enabled: bool,
|
||||
pub breaker_alert_enabled: bool,
|
||||
pub components: Components,
|
||||
// New fields as of 2024-01-20
|
||||
pub powerwall_onboarding_settings_set: bool,
|
||||
pub storm_mode_enabled: bool,
|
||||
pub features: PowerwallFeatures,
|
||||
pub warp_site_number: String,
|
||||
pub go_off_grid_test_banner_enabled: Option<bool>,
|
||||
pub powerwall_tesla_electric_interested_in: Option<bool>,
|
||||
pub vpp_tour_enabled: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct PowerwallFeatures {
|
||||
pub rate_plan_manager_no_pricing_constraint: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
|
@ -84,7 +126,7 @@ pub struct Components {
|
|||
pub solar_type: Option<String>,
|
||||
pub grid: bool,
|
||||
pub load_meter: bool,
|
||||
pub market_type: String,
|
||||
pub market_type: Option<String>,
|
||||
#[serde(default)]
|
||||
pub wall_connectors: Vec<WallConnector>,
|
||||
}
|
||||
|
@ -93,60 +135,9 @@ pub struct Components {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::energy_sites::{CalendarHistoryValues, HistoryKind, HistoryPeriod};
|
||||
use crate::ApiValues;
|
||||
use crate::{ApiValues, PrintResponses, RequestData};
|
||||
use chrono::DateTime;
|
||||
|
||||
#[test]
|
||||
fn energy_match_powerwall() {
|
||||
let json = r#"
|
||||
{
|
||||
"energy_site_id": 1032748243,
|
||||
"resource_type": "battery",
|
||||
"site_name": "1 Railway Pde",
|
||||
"id": "ABC2010-1234",
|
||||
"gateway_id": "3287423824-QWE",
|
||||
"asset_site_id": "123ecd-123ecd-12345-12345",
|
||||
"energy_left": 4394.000000000001,
|
||||
"total_pack_energy": 13494,
|
||||
"percentage_charged": 32.562620423892106,
|
||||
"battery_type": "ac_powerwall",
|
||||
"backup_capable": true,
|
||||
"battery_power": -280,
|
||||
"sync_grid_alert_enabled": true,
|
||||
"breaker_alert_enabled": false,
|
||||
"components": {
|
||||
"battery": true,
|
||||
"battery_type": "ac_powerwall",
|
||||
"solar": true,
|
||||
"solar_type": "pv_panel",
|
||||
"grid": true,
|
||||
"load_meter": true,
|
||||
"market_type": "residential"
|
||||
}
|
||||
}
|
||||
"#;
|
||||
|
||||
if let Product::Powerwall(data) = serde_json::from_str(json).unwrap() {
|
||||
assert_eq!(data.battery_type, "ac_powerwall");
|
||||
assert!(data.backup_capable);
|
||||
assert_eq!(data.battery_power, -280);
|
||||
assert!(data.sync_grid_alert_enabled);
|
||||
assert!(!data.breaker_alert_enabled);
|
||||
assert!(data.components.battery);
|
||||
assert_eq!(
|
||||
data.components.battery_type,
|
||||
Some("ac_powerwall".to_string())
|
||||
);
|
||||
assert!(data.components.solar);
|
||||
assert_eq!(data.components.solar_type, Some("pv_panel".to_string()));
|
||||
assert!(data.components.grid);
|
||||
assert!(data.components.load_meter);
|
||||
assert_eq!(data.components.market_type, "residential");
|
||||
} else {
|
||||
panic!("Expected PowerwallData");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn energy_match_vehicle() {
|
||||
let json = r#"
|
||||
|
@ -274,4 +265,20 @@ mod tests {
|
|||
"https://base.com/e/123/history?period=month&kind=energy&start_date=2020-01-01T00:00:00Z&end_date=2020-01-31T23:59:59Z"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_products_gak_2024_01_20() {
|
||||
let s = include_str!("../testdata/products_gak_2024_01_20.json");
|
||||
let request_data = RequestData::Get { url: "" };
|
||||
OwnerApi::parse_json::<Vec<Product>>(&request_data, s.to_string(), PrintResponses::Pretty)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_products_gak_2024_04_12() {
|
||||
let s = include_str!("../testdata/products_gak_2024_04_12.json");
|
||||
let request_data = RequestData::Get { url: "" };
|
||||
OwnerApi::parse_json::<Vec<Product>>(&request_data, s.to_string(), PrintResponses::Pretty)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ use strum::{Display, EnumString};
|
|||
|
||||
#[rustfmt::skip]
|
||||
impl VehicleApi for OwnerApi {
|
||||
get!(vehicles, Vec<Vehicle>, "/vehicles");
|
||||
get_args!(vehicle_data, VehicleData, "/vehicles/{}/vehicle_data", GetVehicleData);
|
||||
post_arg_empty!(wake_up, "/vehicles/{}/command/wake_up", VehicleId);
|
||||
|
||||
|
@ -547,9 +546,6 @@ pub struct GranularAccess {
|
|||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Vehicles(Vec<Vehicle>);
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct Vehicle {
|
||||
pub id: VehicleId,
|
||||
|
|
|
@ -4,18 +4,18 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
reqwest = "0.11.22"
|
||||
tokio = { version = "1.33.0", features = ["full"] }
|
||||
clap = { version = "4.4.6", features = ["derive"] }
|
||||
scraper = "0.17.1"
|
||||
reqwest = "0.11.23"
|
||||
tokio = { version = "1.35.1", features = ["full"] }
|
||||
clap = { version = "4.4.18", features = ["derive"] }
|
||||
scraper = "0.18.1"
|
||||
strum = { version = "0.25.0", features = ["derive"] }
|
||||
tracing-subscriber = "0.3.17"
|
||||
tracing-subscriber = "0.3.18"
|
||||
tracing = "0.1.40"
|
||||
log = "0.4.20"
|
||||
nom = "7.1.3"
|
||||
anyhow = "1.0.75"
|
||||
serde = { version = "1.0.189", features = ["derive"] }
|
||||
serde_json = "1.0.107"
|
||||
anyhow = "1.0.79"
|
||||
serde = { version = "1.0.195", features = ["derive"] }
|
||||
serde_json = "1.0.111"
|
||||
heck = "0.5.0-rc.1"
|
||||
glob = "0.3.1"
|
||||
syn = { version = "2.0.38" , features = ["full", "extra-traits"] }
|
||||
syn = { version = "2.0.48" , features = ["full", "extra-traits"] }
|
||||
|
|
118
testdata/products_gak_2024_01_20.json
vendored
Normal file
118
testdata/products_gak_2024_01_20.json
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
{
|
||||
"count": 2,
|
||||
"response": [
|
||||
{
|
||||
"access_type": "OWNER",
|
||||
"api_version": 71,
|
||||
"backseat_token": null,
|
||||
"backseat_token_updated_at": null,
|
||||
"ble_autopair_enrolled": false,
|
||||
"cached_data": "",
|
||||
"calendar_enabled": true,
|
||||
"color": null,
|
||||
"command_signing": "required",
|
||||
"display_name": "Kool Beans",
|
||||
"granular_access": {
|
||||
"hide_private": false
|
||||
},
|
||||
"id": 1,
|
||||
"id_s": "1",
|
||||
"in_service": false,
|
||||
"option_codes": null,
|
||||
"release_notes_supported": true,
|
||||
"state": "online",
|
||||
"tokens": [
|
||||
],
|
||||
"user_id": 2,
|
||||
"vehicle_config": {
|
||||
"aux_park_lamps": "Eu",
|
||||
"badge_version": 0,
|
||||
"can_accept_navigation_requests": true,
|
||||
"can_actuate_trunks": true,
|
||||
"car_special_type": "base",
|
||||
"car_type": "model3",
|
||||
"charge_port_type": "CCS",
|
||||
"cop_user_set_temp_supported": false,
|
||||
"dashcam_clip_save_supported": true,
|
||||
"default_charge_to_max": false,
|
||||
"driver_assist": "TeslaAP3",
|
||||
"ece_restrictions": false,
|
||||
"efficiency_package": "M32021",
|
||||
"eu_vehicle": true,
|
||||
"exterior_color": "MidnightSilver",
|
||||
"exterior_trim": "Black",
|
||||
"exterior_trim_override": "",
|
||||
"has_air_suspension": false,
|
||||
"has_ludicrous_mode": false,
|
||||
"has_seat_cooling": false,
|
||||
"headlamp_type": "Global",
|
||||
"interior_trim_type": "Black2",
|
||||
"key_version": 2,
|
||||
"motorized_charge_port": true,
|
||||
"paint_color_override": "24,24,27,0.9,0.3",
|
||||
"performance_package": "Base",
|
||||
"plg": true,
|
||||
"pws": false,
|
||||
"rear_drive_unit": "PM216MOSFET",
|
||||
"rear_seat_heaters": 1,
|
||||
"rear_seat_type": 0,
|
||||
"rhd": true,
|
||||
"roof_color": "RoofColorGlass",
|
||||
"seat_type": null,
|
||||
"spoiler_type": "None",
|
||||
"sun_roof_installed": null,
|
||||
"supports_qr_pairing": false,
|
||||
"third_row_seats": "None",
|
||||
"timestamp": 1705717676876,
|
||||
"trim_badging": "74d",
|
||||
"use_range_badging": true,
|
||||
"utc_offset": 36000,
|
||||
"webcam_selfie_supported": true,
|
||||
"webcam_supported": true,
|
||||
"wheel_type": "StilettoRefresh19"
|
||||
},
|
||||
"vehicle_id": 1,
|
||||
"vin": "LR"
|
||||
},
|
||||
{
|
||||
"asset_site_id": "",
|
||||
"backup_capable": true,
|
||||
"battery_power": 3520,
|
||||
"battery_type": "ac_powerwall",
|
||||
"breaker_alert_enabled": true,
|
||||
"components": {
|
||||
"battery": true,
|
||||
"battery_type": "ac_powerwall",
|
||||
"grid": true,
|
||||
"load_meter": true,
|
||||
"solar": true,
|
||||
"solar_type": "pv_panel",
|
||||
"wall_connectors": [
|
||||
{
|
||||
"device_id": "",
|
||||
"din": "",
|
||||
"is_active": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"energy_left": 13136.26315789474,
|
||||
"energy_site_id": 247079748146,
|
||||
"features": {
|
||||
"rate_plan_manager_no_pricing_constraint": true
|
||||
},
|
||||
"gateway_id": "a",
|
||||
"go_off_grid_test_banner_enabled": null,
|
||||
"id": "1234",
|
||||
"percentage_charged": 31.52375310862408,
|
||||
"powerwall_onboarding_settings_set": true,
|
||||
"powerwall_tesla_electric_interested_in": null,
|
||||
"resource_type": "battery",
|
||||
"site_name": "",
|
||||
"storm_mode_enabled": true,
|
||||
"sync_grid_alert_enabled": true,
|
||||
"total_pack_energy": 41671,
|
||||
"vpp_tour_enabled": null,
|
||||
"warp_site_number": "STE00"
|
||||
}
|
||||
]
|
||||
}
|
70
testdata/products_gak_2024_04_12.json
vendored
Normal file
70
testdata/products_gak_2024_04_12.json
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"count": 2,
|
||||
"response": [
|
||||
{
|
||||
"access_type": "OWNER",
|
||||
"api_version": 73,
|
||||
"backseat_token": null,
|
||||
"backseat_token_updated_at": null,
|
||||
"ble_autopair_enrolled": false,
|
||||
"cached_data": "",
|
||||
"calendar_enabled": true,
|
||||
"color": null,
|
||||
"command_signing": "required",
|
||||
"display_name": "Kool Beans",
|
||||
"granular_access": {
|
||||
"hide_private": false
|
||||
},
|
||||
"id": 123,
|
||||
"id_s": "123",
|
||||
"in_service": false,
|
||||
"option_codes": null,
|
||||
"release_notes_supported": true,
|
||||
"state": "online",
|
||||
"tokens": [],
|
||||
"user_id": 123,
|
||||
"vehicle_id": 123,
|
||||
"vin": "LRW"
|
||||
},
|
||||
{
|
||||
"asset_site_id": "qwfp",
|
||||
"backup_capable": true,
|
||||
"battery_power": -1590,
|
||||
"battery_type": "ac_powerwall",
|
||||
"breaker_alert_enabled": true,
|
||||
"components": {
|
||||
"battery": true,
|
||||
"battery_type": "ac_powerwall",
|
||||
"grid": true,
|
||||
"load_meter": true,
|
||||
"market_type": "residential",
|
||||
"solar": true,
|
||||
"solar_type": "pv_panel",
|
||||
"wall_connectors": [
|
||||
{
|
||||
"device_id": "qwfp",
|
||||
"din": "qwfp",
|
||||
"is_active": true,
|
||||
"part_number": "1529455-02-D"
|
||||
}
|
||||
]
|
||||
},
|
||||
"energy_site_id": 1234,
|
||||
"features": {
|
||||
"rate_plan_manager_no_pricing_constraint": true
|
||||
},
|
||||
"gateway_id": "qwfp",
|
||||
"go_off_grid_test_banner_enabled": null,
|
||||
"id": "qwfp",
|
||||
"percentage_charged": 48.872760297620715,
|
||||
"powerwall_onboarding_settings_set": true,
|
||||
"powerwall_tesla_electric_interested_in": null,
|
||||
"resource_type": "battery",
|
||||
"site_name": "",
|
||||
"storm_mode_enabled": true,
|
||||
"sync_grid_alert_enabled": true,
|
||||
"vpp_tour_enabled": null,
|
||||
"warp_site_number": ""
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in a new issue