feat: support registered wall connectors
This commit is contained in:
parent
36572f1ce2
commit
eec64e3e7b
|
@ -12,7 +12,7 @@ impl OwnerApi {
|
|||
pub_get_args!(energy_sites_calendar_history, CalendarHistory, "/energy_sites/{}/calendar_history", CalendarHistoryValues);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct SiteStatus {
|
||||
pub backup_capable: bool,
|
||||
pub battery_power: i64,
|
||||
|
@ -32,7 +32,7 @@ pub struct SiteStatus {
|
|||
pub total_pack_energy: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct LiveStatus {
|
||||
pub backup_capable: bool,
|
||||
pub battery_power: i64,
|
||||
|
@ -49,10 +49,31 @@ pub struct LiveStatus {
|
|||
pub storm_mode_active: bool,
|
||||
pub timestamp: String,
|
||||
pub total_pack_energy: i64,
|
||||
pub wall_connectors: Vec<()>, // TODO: gak: This is empty so I don't know what it looks like.
|
||||
pub wall_connectors: Vec<LiveWallConnector>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct WallConnector {
|
||||
pub device_id: String,
|
||||
pub din: String,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct LiveWallConnector {
|
||||
/// VIN of the car when connected to the wall connector.
|
||||
pub vin: Option<String>,
|
||||
pub din: String,
|
||||
|
||||
/// Observed:
|
||||
/// 2: not plugged in
|
||||
/// 4: plugged in (not charging)
|
||||
pub wall_connector_state: i64,
|
||||
pub wall_connector_power: i64,
|
||||
pub wall_connector_fault_state: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct UserSettings {
|
||||
pub breaker_alert_enabled: bool,
|
||||
pub powerwall_onboarding_settings_set: bool,
|
||||
|
@ -61,7 +82,7 @@ pub struct UserSettings {
|
|||
pub sync_grid_alert_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct Schedule {
|
||||
pub end_seconds: i64,
|
||||
pub start_seconds: i64,
|
||||
|
@ -69,20 +90,20 @@ pub struct Schedule {
|
|||
pub week_days: Vec<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct TouSettings {
|
||||
pub optimization_strategy: String,
|
||||
pub schedule: Vec<Schedule>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct Geolocation {
|
||||
pub latitude: f64,
|
||||
pub longitude: f64,
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct Components {
|
||||
pub backup: bool,
|
||||
pub backup_time_remaining_enabled: bool,
|
||||
|
@ -115,7 +136,7 @@ pub struct Components {
|
|||
pub wifi_commissioning_enabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct Address {
|
||||
pub address_line1: String,
|
||||
pub city: String,
|
||||
|
@ -124,7 +145,7 @@ pub struct Address {
|
|||
pub zip: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct SiteInfo {
|
||||
pub address: Address,
|
||||
pub backup_reserve_percent: i64,
|
||||
|
@ -192,7 +213,7 @@ impl Values for CalendarHistoryValues {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct CalendarHistory {
|
||||
pub serial_number: String,
|
||||
/// Only appears in energy kind.
|
||||
|
@ -202,14 +223,14 @@ pub struct CalendarHistory {
|
|||
pub time_series: Option<Vec<Series>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
#[serde(untagged)]
|
||||
pub enum Series {
|
||||
Power(PowerSeries),
|
||||
Energy(EnergySeries),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct PowerSeries {
|
||||
pub timestamp: DateTime<FixedOffset>,
|
||||
pub solar_power: f64,
|
||||
|
@ -219,7 +240,7 @@ pub struct PowerSeries {
|
|||
pub generator_power: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq)]
|
||||
pub struct EnergySeries {
|
||||
pub timestamp: DateTime<FixedOffset>,
|
||||
pub solar_energy_exported: f64,
|
||||
|
@ -239,3 +260,85 @@ pub struct EnergySeries {
|
|||
pub consumer_energy_imported_from_battery: f64,
|
||||
pub consumer_energy_imported_from_generator: f64,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::energy_sites::{LiveStatus, LiveWallConnector, WallConnector};
|
||||
use crate::products::Product;
|
||||
use crate::{OwnerApi, PrintResponses, RequestData};
|
||||
|
||||
#[test]
|
||||
fn json_energy_sites_gak_2023_11_06() {
|
||||
let s = include_str!("../testdata/energy_sites_gak_2023_11_06.json");
|
||||
|
||||
let request_data = RequestData::Get { url: "" };
|
||||
let products = OwnerApi::parse_json::<Vec<Product>>(
|
||||
&request_data,
|
||||
s.to_string(),
|
||||
PrintResponses::Pretty,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let Product::Powerwall(powerwall) = &products[1] else {
|
||||
panic!("Expected Powerwall product");
|
||||
};
|
||||
assert_eq!(
|
||||
powerwall.components.wall_connectors[0],
|
||||
WallConnector {
|
||||
device_id: "uuid".to_string(),
|
||||
din: "12345".to_string(),
|
||||
is_active: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_energy_sites_live_power_gak_2023_11_06() {
|
||||
let s = include_str!("../testdata/energy_sites_live_status_gak_plugged_in_2023_11_06.json");
|
||||
|
||||
let request_data = RequestData::Get { url: "" };
|
||||
let live_status = OwnerApi::parse_json::<LiveStatus>(
|
||||
&request_data,
|
||||
s.to_string(),
|
||||
PrintResponses::Pretty,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let wall_connector = live_status.wall_connectors.first().unwrap();
|
||||
assert_eq!(
|
||||
wall_connector,
|
||||
&LiveWallConnector {
|
||||
vin: Some("1234".to_string()),
|
||||
din: "5432".to_string(),
|
||||
wall_connector_state: 4,
|
||||
wall_connector_power: 0,
|
||||
wall_connector_fault_state: 2,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_energy_sites_live_power_unplugged_charger_gak_2023_11_06() {
|
||||
let s = include_str!("../testdata/energy_sites_live_status_gak_unplugged_2023_11_06.json");
|
||||
|
||||
let request_data = RequestData::Get { url: "" };
|
||||
let live_status = OwnerApi::parse_json::<LiveStatus>(
|
||||
&request_data,
|
||||
s.to_string(),
|
||||
PrintResponses::Pretty,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let wall_connector = live_status.wall_connectors.first().unwrap();
|
||||
assert_eq!(
|
||||
wall_connector,
|
||||
&LiveWallConnector {
|
||||
vin: None,
|
||||
din: "1234".to_string(),
|
||||
wall_connector_state: 2,
|
||||
wall_connector_power: 0,
|
||||
wall_connector_fault_state: 2,
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::energy_sites::WallConnector;
|
||||
use crate::error::TeslatteError;
|
||||
use crate::powerwall::PowerwallId;
|
||||
use crate::vehicles::VehicleData;
|
||||
|
@ -79,6 +80,8 @@ pub struct Components {
|
|||
pub grid: bool,
|
||||
pub load_meter: bool,
|
||||
pub market_type: String,
|
||||
#[serde(default)]
|
||||
pub wall_connectors: Vec<WallConnector>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
120
testdata/energy_sites_gak_2023_11_06.json
vendored
Normal file
120
testdata/energy_sites_gak_2023_11_06.json
vendored
Normal file
|
@ -0,0 +1,120 @@
|
|||
{
|
||||
"count": 2,
|
||||
"response": [
|
||||
{
|
||||
"access_type": "OWNER",
|
||||
"api_version": 63,
|
||||
"backseat_token": null,
|
||||
"backseat_token_updated_at": null,
|
||||
"ble_autopair_enrolled": false,
|
||||
"cached_data": "",
|
||||
"calendar_enabled": true,
|
||||
"color": null,
|
||||
"command_signing": "required",
|
||||
"display_name": "Carname",
|
||||
"granular_access": {
|
||||
"hide_private": false
|
||||
},
|
||||
"id": 123456,
|
||||
"id_s": "123546",
|
||||
"in_service": false,
|
||||
"option_codes": null,
|
||||
"release_notes_supported": true,
|
||||
"state": "online",
|
||||
"tokens": [
|
||||
"123",
|
||||
"123"
|
||||
],
|
||||
"user_id": 1234,
|
||||
"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": 1699226972553,
|
||||
"trim_badging": "74d",
|
||||
"use_range_badging": true,
|
||||
"utc_offset": 36000,
|
||||
"webcam_selfie_supported": true,
|
||||
"webcam_supported": true,
|
||||
"wheel_type": "StilettoRefresh19"
|
||||
},
|
||||
"vehicle_id": 123,
|
||||
"vin": "1234"
|
||||
},
|
||||
{
|
||||
"asset_site_id": "uuid",
|
||||
"backup_capable": true,
|
||||
"battery_power": -13520,
|
||||
"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": "uuid",
|
||||
"din": "12345",
|
||||
"is_active": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"energy_left": 36696.68421052631,
|
||||
"energy_site_id": 12345,
|
||||
"features": {
|
||||
"rate_plan_manager_no_pricing_constraint": true
|
||||
},
|
||||
"gateway_id": "12345",
|
||||
"go_off_grid_test_banner_enabled": null,
|
||||
"id": "12345",
|
||||
"percentage_charged": 87.61713394581648,
|
||||
"powerwall_onboarding_settings_set": true,
|
||||
"powerwall_tesla_electric_interested_in": null,
|
||||
"resource_type": "battery",
|
||||
"site_name": "address",
|
||||
"storm_mode_enabled": true,
|
||||
"sync_grid_alert_enabled": true,
|
||||
"total_pack_energy": 41883,
|
||||
"warp_site_number": "1234"
|
||||
}
|
||||
]
|
||||
}
|
28
testdata/energy_sites_live_status_gak_plugged_in_2023_11_06.json
vendored
Normal file
28
testdata/energy_sites_live_status_gak_plugged_in_2023_11_06.json
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"response": {
|
||||
"backup_capable": true,
|
||||
"battery_power": -13950,
|
||||
"energy_left": 37784.05263157895,
|
||||
"generator_power": 0,
|
||||
"grid_power": 0,
|
||||
"grid_services_active": false,
|
||||
"grid_services_power": 0,
|
||||
"grid_status": "Active",
|
||||
"island_status": "on_grid",
|
||||
"load_power": 2226,
|
||||
"percentage_charged": 90.21333866145918,
|
||||
"solar_power": 16176,
|
||||
"storm_mode_active": false,
|
||||
"timestamp": "2023-11-06T10:30:11+11:00",
|
||||
"total_pack_energy": 41883,
|
||||
"wall_connectors": [
|
||||
{
|
||||
"din": "5432",
|
||||
"vin": "1234",
|
||||
"wall_connector_fault_state": 2,
|
||||
"wall_connector_power": 0,
|
||||
"wall_connector_state": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
27
testdata/energy_sites_live_status_gak_unplugged_2023_11_06.json
vendored
Normal file
27
testdata/energy_sites_live_status_gak_unplugged_2023_11_06.json
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"response": {
|
||||
"backup_capable": true,
|
||||
"battery_power": 0,
|
||||
"energy_left": 41880,
|
||||
"generator_power": 0,
|
||||
"grid_power": -12949,
|
||||
"grid_services_active": false,
|
||||
"grid_services_power": 0,
|
||||
"grid_status": "Active",
|
||||
"island_status": "on_grid",
|
||||
"load_power": 3905,
|
||||
"percentage_charged": 100,
|
||||
"solar_power": 16854,
|
||||
"storm_mode_active": false,
|
||||
"timestamp": "2023-11-06T11:51:17+11:00",
|
||||
"total_pack_energy": 41880,
|
||||
"wall_connectors": [
|
||||
{
|
||||
"din": "1234",
|
||||
"wall_connector_fault_state": 2,
|
||||
"wall_connector_power": 0,
|
||||
"wall_connector_state": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue