From 6f9e39cd3f5106f38a41f560189ae5008ea01d85 Mon Sep 17 00:00:00 2001 From: Brett Adams Date: Sat, 20 Jul 2024 19:22:15 +1000 Subject: [PATCH] Add diagnostics to Tesla Fleet (#122223) --- .../components/tesla_fleet/diagnostics.py | 54 +++ .../snapshots/test_diagnostics.ambr | 436 ++++++++++++++++++ .../tesla_fleet/test_diagnostics.py | 27 ++ 3 files changed, 517 insertions(+) create mode 100644 homeassistant/components/tesla_fleet/diagnostics.py create mode 100644 tests/components/tesla_fleet/snapshots/test_diagnostics.ambr create mode 100644 tests/components/tesla_fleet/test_diagnostics.py diff --git a/homeassistant/components/tesla_fleet/diagnostics.py b/homeassistant/components/tesla_fleet/diagnostics.py new file mode 100644 index 00000000000..0dc4cddbfc9 --- /dev/null +++ b/homeassistant/components/tesla_fleet/diagnostics.py @@ -0,0 +1,54 @@ +"""Provides diagnostics for Tesla Fleet.""" + +from __future__ import annotations + +from typing import Any + +from homeassistant.components.diagnostics import async_redact_data +from homeassistant.core import HomeAssistant + +from . import TeslaFleetConfigEntry + +VEHICLE_REDACT = [ + "id", + "user_id", + "vehicle_id", + "vin", + "tokens", + "id_s", + "drive_state_active_route_latitude", + "drive_state_active_route_longitude", + "drive_state_latitude", + "drive_state_longitude", + "drive_state_native_latitude", + "drive_state_native_longitude", +] + +ENERGY_LIVE_REDACT = ["vin"] +ENERGY_INFO_REDACT = ["installation_date", "serial_number"] + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, entry: TeslaFleetConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + vehicles = [ + { + "data": async_redact_data(x.coordinator.data, VEHICLE_REDACT), + } + for x in entry.runtime_data.vehicles + ] + energysites = [ + { + "live": async_redact_data(x.live_coordinator.data, ENERGY_LIVE_REDACT), + "info": async_redact_data(x.info_coordinator.data, ENERGY_INFO_REDACT), + } + for x in entry.runtime_data.energysites + ] + + # Return only the relevant children + return { + "vehicles": vehicles, + "energysites": energysites, + "scopes": entry.runtime_data.scopes, + } diff --git a/tests/components/tesla_fleet/snapshots/test_diagnostics.ambr b/tests/components/tesla_fleet/snapshots/test_diagnostics.ambr new file mode 100644 index 00000000000..902c7af131e --- /dev/null +++ b/tests/components/tesla_fleet/snapshots/test_diagnostics.ambr @@ -0,0 +1,436 @@ +# serializer version: 1 +# name: test_diagnostics + dict({ + 'energysites': list([ + dict({ + 'info': dict({ + 'backup_reserve_percent': 0, + 'battery_count': 2, + 'components_backup': True, + 'components_backup_time_remaining_enabled': True, + 'components_batteries': list([ + dict({ + 'device_id': 'battery-1-id', + 'din': 'battery-1-din', + 'nameplate_energy': 13500, + 'nameplate_max_charge_power': 5000, + 'nameplate_max_discharge_power': 5000, + 'part_name': 'Powerwall 2', + 'part_number': '3012170-10-B', + 'part_type': 2, + 'serial_number': '**REDACTED**', + }), + dict({ + 'device_id': 'battery-2-id', + 'din': 'battery-2-din', + 'nameplate_energy': 13500, + 'nameplate_max_charge_power': 5000, + 'nameplate_max_discharge_power': 5000, + 'part_name': 'Powerwall 2', + 'part_number': '3012170-05-C', + 'part_type': 2, + 'serial_number': '**REDACTED**', + }), + ]), + 'components_battery': True, + 'components_battery_solar_offset_view_enabled': True, + 'components_battery_type': 'ac_powerwall', + 'components_car_charging_data_supported': False, + 'components_configurable': True, + 'components_customer_preferred_export_rule': 'pv_only', + 'components_disallow_charge_from_grid_with_solar_installed': True, + 'components_energy_service_self_scheduling_enabled': True, + 'components_energy_value_header': 'Energy Value', + 'components_energy_value_subheader': 'Estimated Value', + 'components_flex_energy_request_capable': False, + 'components_gateway': 'teg', + 'components_gateways': list([ + dict({ + 'device_id': 'gateway-id', + 'din': 'gateway-din', + 'firmware_version': '24.4.0 0fe780c9', + 'is_active': True, + 'part_name': 'Tesla Backup Gateway 2', + 'part_number': '1152100-14-J', + 'part_type': 10, + 'serial_number': '**REDACTED**', + 'site_id': '1234-abcd', + 'updated_datetime': '2024-05-14T00:00:00.000Z', + }), + ]), + 'components_grid': True, + 'components_grid_services_enabled': False, + 'components_load_meter': True, + 'components_net_meter_mode': 'battery_ok', + 'components_off_grid_vehicle_charging_reserve_supported': True, + 'components_set_islanding_mode_enabled': True, + 'components_show_grid_import_battery_source_cards': True, + 'components_solar': True, + 'components_solar_type': 'pv_panel', + 'components_solar_value_enabled': True, + 'components_storm_mode_capable': True, + 'components_system_alerts_enabled': True, + 'components_tou_capable': True, + 'components_vehicle_charging_performance_view_enabled': False, + 'components_vehicle_charging_solar_offset_view_enabled': False, + 'components_wall_connectors': list([ + dict({ + 'device_id': '123abc', + 'din': 'abd-123', + 'is_active': True, + 'part_name': 'Gen 3 Wall Connector', + }), + dict({ + 'device_id': '234bcd', + 'din': 'bcd-234', + 'is_active': True, + 'part_name': 'Gen 3 Wall Connector', + }), + ]), + 'components_wifi_commissioning_enabled': True, + 'default_real_mode': 'self_consumption', + 'id': '1233-abcd', + 'installation_date': '**REDACTED**', + 'installation_time_zone': '', + 'max_site_meter_power_ac': 1000000000, + 'min_site_meter_power_ac': -1000000000, + 'nameplate_energy': 40500, + 'nameplate_power': 15000, + 'site_name': 'Site', + 'tou_settings_optimization_strategy': 'economics', + 'tou_settings_schedule': list([ + dict({ + 'end_seconds': 3600, + 'start_seconds': 0, + 'target': 'off_peak', + 'week_days': list([ + 1, + 0, + ]), + }), + dict({ + 'end_seconds': 0, + 'start_seconds': 3600, + 'target': 'peak', + 'week_days': list([ + 1, + 0, + ]), + }), + ]), + 'user_settings_breaker_alert_enabled': False, + 'user_settings_go_off_grid_test_banner_enabled': False, + 'user_settings_powerwall_onboarding_settings_set': True, + 'user_settings_powerwall_tesla_electric_interested_in': False, + 'user_settings_storm_mode_enabled': True, + 'user_settings_sync_grid_alert_enabled': True, + 'user_settings_vpp_tour_enabled': True, + 'version': '23.44.0 eb113390', + 'vpp_backup_reserve_percent': 0, + }), + 'live': dict({ + 'backup_capable': True, + 'battery_power': 5060, + 'energy_left': 38896.47368421053, + 'generator_power': 0, + 'grid_power': 0, + 'grid_services_active': False, + 'grid_services_power': 0, + 'grid_status': 'Active', + 'island_status': 'on_grid', + 'load_power': 6245, + 'percentage_charged': 95.50537403739663, + 'solar_power': 1185, + 'storm_mode_active': False, + 'timestamp': '2024-01-01T00:00:00+00:00', + 'total_pack_energy': 40727, + 'wall_connectors': dict({ + 'abd-123': dict({ + 'din': 'abd-123', + 'wall_connector_fault_state': 2, + 'wall_connector_power': 0, + 'wall_connector_state': 2, + }), + 'bcd-234': dict({ + 'din': 'bcd-234', + 'wall_connector_fault_state': 2, + 'wall_connector_power': 0, + 'wall_connector_state': 2, + }), + }), + }), + }), + ]), + 'scopes': list([ + 'openid', + 'offline_access', + 'vehicle_device_data', + 'vehicle_cmds', + 'vehicle_charging_cmds', + 'energy_device_data', + 'energy_cmds', + ]), + 'vehicles': list([ + dict({ + 'data': dict({ + 'access_type': 'OWNER', + 'api_version': 71, + 'backseat_token': None, + 'backseat_token_updated_at': None, + 'ble_autopair_enrolled': False, + 'calendar_enabled': True, + 'charge_state_battery_heater_on': False, + 'charge_state_battery_level': 77, + 'charge_state_battery_range': 266.87, + 'charge_state_charge_amps': 16, + 'charge_state_charge_current_request': 16, + 'charge_state_charge_current_request_max': 16, + 'charge_state_charge_enable_request': True, + 'charge_state_charge_energy_added': 0, + 'charge_state_charge_limit_soc': 80, + 'charge_state_charge_limit_soc_max': 100, + 'charge_state_charge_limit_soc_min': 50, + 'charge_state_charge_limit_soc_std': 80, + 'charge_state_charge_miles_added_ideal': 0, + 'charge_state_charge_miles_added_rated': 0, + 'charge_state_charge_port_cold_weather_mode': False, + 'charge_state_charge_port_color': '', + 'charge_state_charge_port_door_open': True, + 'charge_state_charge_port_latch': 'Engaged', + 'charge_state_charge_rate': 0, + 'charge_state_charger_actual_current': 0, + 'charge_state_charger_phases': None, + 'charge_state_charger_pilot_current': 16, + 'charge_state_charger_power': 0, + 'charge_state_charger_voltage': 2, + 'charge_state_charging_state': 'Stopped', + 'charge_state_conn_charge_cable': 'IEC', + 'charge_state_est_battery_range': 275.04, + 'charge_state_fast_charger_brand': '', + 'charge_state_fast_charger_present': False, + 'charge_state_fast_charger_type': 'ACSingleWireCAN', + 'charge_state_ideal_battery_range': 266.87, + 'charge_state_max_range_charge_counter': 0, + 'charge_state_minutes_to_full_charge': 0, + 'charge_state_not_enough_power_to_heat': None, + 'charge_state_off_peak_charging_enabled': False, + 'charge_state_off_peak_charging_times': 'all_week', + 'charge_state_off_peak_hours_end_time': 900, + 'charge_state_preconditioning_enabled': False, + 'charge_state_preconditioning_times': 'all_week', + 'charge_state_scheduled_charging_mode': 'Off', + 'charge_state_scheduled_charging_pending': False, + 'charge_state_scheduled_charging_start_time': None, + 'charge_state_scheduled_charging_start_time_app': 600, + 'charge_state_scheduled_departure_time': 1704837600, + 'charge_state_scheduled_departure_time_minutes': 480, + 'charge_state_supercharger_session_trip_planner': False, + 'charge_state_time_to_full_charge': 0, + 'charge_state_timestamp': 1705707520649, + 'charge_state_trip_charging': False, + 'charge_state_usable_battery_level': 77, + 'charge_state_user_charge_enable_request': None, + 'climate_state_allow_cabin_overheat_protection': True, + 'climate_state_auto_seat_climate_left': True, + 'climate_state_auto_seat_climate_right': True, + 'climate_state_auto_steering_wheel_heat': False, + 'climate_state_battery_heater': False, + 'climate_state_battery_heater_no_power': None, + 'climate_state_cabin_overheat_protection': 'On', + 'climate_state_cabin_overheat_protection_actively_cooling': False, + 'climate_state_climate_keeper_mode': 'keep', + 'climate_state_cop_activation_temperature': 'High', + 'climate_state_defrost_mode': 0, + 'climate_state_driver_temp_setting': 22, + 'climate_state_fan_status': 0, + 'climate_state_hvac_auto_request': 'On', + 'climate_state_inside_temp': 29.8, + 'climate_state_is_auto_conditioning_on': False, + 'climate_state_is_climate_on': True, + 'climate_state_is_front_defroster_on': False, + 'climate_state_is_preconditioning': False, + 'climate_state_is_rear_defroster_on': False, + 'climate_state_left_temp_direction': 251, + 'climate_state_max_avail_temp': 28, + 'climate_state_min_avail_temp': 15, + 'climate_state_outside_temp': 30, + 'climate_state_passenger_temp_setting': 22, + 'climate_state_remote_heater_control_enabled': False, + 'climate_state_right_temp_direction': 251, + 'climate_state_seat_heater_left': 0, + 'climate_state_seat_heater_rear_center': 0, + 'climate_state_seat_heater_rear_left': 0, + 'climate_state_seat_heater_rear_right': 0, + 'climate_state_seat_heater_right': 0, + 'climate_state_side_mirror_heaters': False, + 'climate_state_steering_wheel_heat_level': 0, + 'climate_state_steering_wheel_heater': False, + 'climate_state_supports_fan_only_cabin_overheat_protection': True, + 'climate_state_timestamp': 1705707520649, + 'climate_state_wiper_blade_heater': False, + 'color': None, + 'drive_state_active_route_latitude': '**REDACTED**', + 'drive_state_active_route_longitude': '**REDACTED**', + 'drive_state_active_route_miles_to_arrival': 0.039491, + 'drive_state_active_route_minutes_to_arrival': 0.103577, + 'drive_state_active_route_traffic_minutes_delay': 0, + 'drive_state_gps_as_of': 1701129612, + 'drive_state_heading': 185, + 'drive_state_latitude': '**REDACTED**', + 'drive_state_longitude': '**REDACTED**', + 'drive_state_native_latitude': '**REDACTED**', + 'drive_state_native_location_supported': 1, + 'drive_state_native_longitude': '**REDACTED**', + 'drive_state_native_type': 'wgs', + 'drive_state_power': -7, + 'drive_state_shift_state': None, + 'drive_state_speed': None, + 'drive_state_timestamp': 1705707520649, + 'granular_access_hide_private': False, + 'gui_settings_gui_24_hour_time': False, + 'gui_settings_gui_charge_rate_units': 'kW', + 'gui_settings_gui_distance_units': 'km/hr', + 'gui_settings_gui_range_display': 'Rated', + 'gui_settings_gui_temperature_units': 'C', + 'gui_settings_gui_tirepressure_units': 'Psi', + 'gui_settings_show_range_units': False, + 'gui_settings_timestamp': 1705707520649, + 'id': '**REDACTED**', + 'id_s': '**REDACTED**', + 'in_service': False, + 'state': 'online', + 'tokens': '**REDACTED**', + 'user_id': '**REDACTED**', + 'vehicle_config_aux_park_lamps': 'Eu', + 'vehicle_config_badge_version': 1, + 'vehicle_config_can_accept_navigation_requests': True, + 'vehicle_config_can_actuate_trunks': True, + 'vehicle_config_car_special_type': 'base', + 'vehicle_config_car_type': 'model3', + 'vehicle_config_charge_port_type': 'CCS', + 'vehicle_config_cop_user_set_temp_supported': True, + 'vehicle_config_dashcam_clip_save_supported': True, + 'vehicle_config_default_charge_to_max': False, + 'vehicle_config_driver_assist': 'TeslaAP3', + 'vehicle_config_ece_restrictions': False, + 'vehicle_config_efficiency_package': 'M32021', + 'vehicle_config_eu_vehicle': True, + 'vehicle_config_exterior_color': 'DeepBlue', + 'vehicle_config_exterior_trim': 'Black', + 'vehicle_config_exterior_trim_override': '', + 'vehicle_config_has_air_suspension': False, + 'vehicle_config_has_ludicrous_mode': False, + 'vehicle_config_has_seat_cooling': False, + 'vehicle_config_headlamp_type': 'Global', + 'vehicle_config_interior_trim_type': 'White2', + 'vehicle_config_key_version': 2, + 'vehicle_config_motorized_charge_port': True, + 'vehicle_config_paint_color_override': '0,9,25,0.7,0.04', + 'vehicle_config_performance_package': 'Base', + 'vehicle_config_plg': True, + 'vehicle_config_pws': True, + 'vehicle_config_rear_drive_unit': 'PM216MOSFET', + 'vehicle_config_rear_seat_heaters': 1, + 'vehicle_config_rear_seat_type': 0, + 'vehicle_config_rhd': True, + 'vehicle_config_roof_color': 'RoofColorGlass', + 'vehicle_config_seat_type': None, + 'vehicle_config_spoiler_type': 'None', + 'vehicle_config_sun_roof_installed': True, + 'vehicle_config_supports_qr_pairing': False, + 'vehicle_config_third_row_seats': 'None', + 'vehicle_config_timestamp': 1705707520649, + 'vehicle_config_trim_badging': '74d', + 'vehicle_config_use_range_badging': True, + 'vehicle_config_utc_offset': 36000, + 'vehicle_config_webcam_selfie_supported': True, + 'vehicle_config_webcam_supported': True, + 'vehicle_config_wheel_type': 'Pinwheel18CapKit', + 'vehicle_id': '**REDACTED**', + 'vehicle_state_api_version': 71, + 'vehicle_state_autopark_state_v2': 'unavailable', + 'vehicle_state_calendar_supported': True, + 'vehicle_state_car_version': '2023.44.30.8 06f534d46010', + 'vehicle_state_center_display_state': 0, + 'vehicle_state_dashcam_clip_save_available': True, + 'vehicle_state_dashcam_state': 'Recording', + 'vehicle_state_df': 0, + 'vehicle_state_dr': 0, + 'vehicle_state_fd_window': 0, + 'vehicle_state_feature_bitmask': 'fbdffbff,187f', + 'vehicle_state_fp_window': 0, + 'vehicle_state_ft': 0, + 'vehicle_state_is_user_present': False, + 'vehicle_state_locked': False, + 'vehicle_state_media_info_a2dp_source_name': 'Pixel 8 Pro', + 'vehicle_state_media_info_audio_volume': 1.6667, + 'vehicle_state_media_info_audio_volume_increment': 0.333333, + 'vehicle_state_media_info_audio_volume_max': 10.333333, + 'vehicle_state_media_info_media_playback_status': 'Playing', + 'vehicle_state_media_info_now_playing_album': 'Elon Musk', + 'vehicle_state_media_info_now_playing_artist': 'Walter Isaacson', + 'vehicle_state_media_info_now_playing_duration': 651000, + 'vehicle_state_media_info_now_playing_elapsed': 1000, + 'vehicle_state_media_info_now_playing_source': 'Audible', + 'vehicle_state_media_info_now_playing_station': 'Elon Musk', + 'vehicle_state_media_info_now_playing_title': 'Chapter 51: Cybertruck: Tesla, 2018–2019', + 'vehicle_state_media_state_remote_control_enabled': True, + 'vehicle_state_notifications_supported': True, + 'vehicle_state_odometer': 6481.019282, + 'vehicle_state_parsed_calendar_supported': True, + 'vehicle_state_pf': 0, + 'vehicle_state_pr': 0, + 'vehicle_state_rd_window': 0, + 'vehicle_state_remote_start': False, + 'vehicle_state_remote_start_enabled': True, + 'vehicle_state_remote_start_supported': True, + 'vehicle_state_rp_window': 0, + 'vehicle_state_rt': 0, + 'vehicle_state_santa_mode': 0, + 'vehicle_state_sentry_mode': False, + 'vehicle_state_sentry_mode_available': True, + 'vehicle_state_service_mode': False, + 'vehicle_state_service_mode_plus': False, + 'vehicle_state_software_update_download_perc': 100, + 'vehicle_state_software_update_expected_duration_sec': 2700, + 'vehicle_state_software_update_install_perc': 1, + 'vehicle_state_software_update_status': 'available', + 'vehicle_state_software_update_version': '2024.12.0.0', + 'vehicle_state_speed_limit_mode_active': False, + 'vehicle_state_speed_limit_mode_current_limit_mph': 69, + 'vehicle_state_speed_limit_mode_max_limit_mph': 120, + 'vehicle_state_speed_limit_mode_min_limit_mph': 50, + 'vehicle_state_speed_limit_mode_pin_code_set': True, + 'vehicle_state_sun_roof_state': 'open', + 'vehicle_state_timestamp': 1705707520649, + 'vehicle_state_tpms_hard_warning_fl': False, + 'vehicle_state_tpms_hard_warning_fr': False, + 'vehicle_state_tpms_hard_warning_rl': False, + 'vehicle_state_tpms_hard_warning_rr': False, + 'vehicle_state_tpms_last_seen_pressure_time_fl': 1705700812, + 'vehicle_state_tpms_last_seen_pressure_time_fr': 1705700793, + 'vehicle_state_tpms_last_seen_pressure_time_rl': 1705700794, + 'vehicle_state_tpms_last_seen_pressure_time_rr': 1705700823, + 'vehicle_state_tpms_pressure_fl': 2.775, + 'vehicle_state_tpms_pressure_fr': 2.8, + 'vehicle_state_tpms_pressure_rl': 2.775, + 'vehicle_state_tpms_pressure_rr': 2.775, + 'vehicle_state_tpms_rcp_front_value': 2.9, + 'vehicle_state_tpms_rcp_rear_value': 2.9, + 'vehicle_state_tpms_soft_warning_fl': False, + 'vehicle_state_tpms_soft_warning_fr': False, + 'vehicle_state_tpms_soft_warning_rl': False, + 'vehicle_state_tpms_soft_warning_rr': False, + 'vehicle_state_valet_mode': False, + 'vehicle_state_valet_pin_needed': False, + 'vehicle_state_vehicle_name': 'Test', + 'vehicle_state_vehicle_self_test_progress': 0, + 'vehicle_state_vehicle_self_test_requested': False, + 'vehicle_state_vehicle_state_sun_roof_percent_open': 20, + 'vehicle_state_webcam_available': True, + 'vin': '**REDACTED**', + }), + }), + ]), + }) +# --- diff --git a/tests/components/tesla_fleet/test_diagnostics.py b/tests/components/tesla_fleet/test_diagnostics.py new file mode 100644 index 00000000000..e0ef24097bb --- /dev/null +++ b/tests/components/tesla_fleet/test_diagnostics.py @@ -0,0 +1,27 @@ +"""Test the Tesla Fleet Diagnostics.""" + +from syrupy.assertion import SnapshotAssertion + +from homeassistant.core import HomeAssistant + +from . import setup_platform + +from tests.common import MockConfigEntry +from tests.components.diagnostics import get_diagnostics_for_config_entry +from tests.typing import ClientSessionGenerator + + +async def test_diagnostics( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + snapshot: SnapshotAssertion, + normal_config_entry: MockConfigEntry, +) -> None: + """Test diagnostics.""" + + await setup_platform(hass, normal_config_entry) + + diag = await get_diagnostics_for_config_entry( + hass, hass_client, normal_config_entry + ) + assert diag == snapshot