From f40c6b3d39df50a6cfd8d5c30a3c334f8fa6f701 Mon Sep 17 00:00:00 2001 From: "Alan D. Tse" Date: Sat, 16 Oct 2021 15:36:13 -0700 Subject: [PATCH] refactor: switch to api convenience function Uses data from https://github.com/tdorssers/TeslaPy/blob/master/teslapy/endpoints.json closes #216 --- teslajsonpy/connection.py | 8 +- teslajsonpy/controller.py | 124 +- teslajsonpy/endpoints.json | 1353 +++++++++++++++++ teslajsonpy/homeassistant/charger.py | 16 +- teslajsonpy/homeassistant/climate.py | 25 +- teslajsonpy/homeassistant/heated_seats.py | 9 +- .../homeassistant/heated_steering_wheel.py | 8 +- teslajsonpy/homeassistant/lock.py | 24 +- teslajsonpy/homeassistant/sentry_mode.py | 14 +- teslajsonpy/homeassistant/trunk.py | 28 +- tests/tesla_mock.py | 11 + 11 files changed, 1547 insertions(+), 73 deletions(-) create mode 100644 teslajsonpy/endpoints.json diff --git a/teslajsonpy/connection.py b/teslajsonpy/connection.py index 136f9be3..6b61285d 100644 --- a/teslajsonpy/connection.py +++ b/teslajsonpy/connection.py @@ -90,7 +90,7 @@ async def get(self, command): """Get data from API.""" return await self.post(command, "get", None) - async def post(self, command, method="post", data=None): + async def post(self, command, method="post", data=None, url=""): """Post data to API.""" now = calendar.timegm(datetime.datetime.now().timetuple()) _LOGGER.debug( @@ -162,8 +162,10 @@ async def post(self, command, method="post", data=None): ) self.token_refreshed = True _LOGGER.debug("Successfully refreshed oauth") + if not url: + url = f"{self.api}{command}" return await self.__open( - f"{self.api}{command}", method=method, headers=self.head, data=data + url, method=method, headers=self.head, data=data ) def __sethead(self, access_token: Text, expires_in: int = 30, expiration: int = 0): @@ -193,7 +195,7 @@ async def __open( cookies = cookies or {} if not baseurl: baseurl = self.baseurl - url: URL = URL(baseurl + url) + url: URL = URL(baseurl).join(URL(url)) _LOGGER.debug("%s: %s %s", method, url, data) diff --git a/teslajsonpy/controller.py b/teslajsonpy/controller.py index 6de387d6..6e32e22e 100644 --- a/teslajsonpy/controller.py +++ b/teslajsonpy/controller.py @@ -10,6 +10,8 @@ """ import asyncio import logging +import json +import pkgutil import time from typing import Callable, Dict, List, Optional, Text @@ -119,11 +121,19 @@ def valid_result(result): result is True or ( isinstance(result, dict) - and isinstance(result["response"], dict) and ( - result["response"].get("result") is True - or result["response"].get("reason") - != "could_not_wake_buses" + ( + isinstance(result["response"], dict) + and ( + result["response"].get("result") is True + or result["response"].get("reason") + != "could_not_wake_buses" + ) + or ( + isinstance(result, dict) + and isinstance(result["response"], list) + ) + ) ) ) ) @@ -134,12 +144,21 @@ def valid_result(result): retries = 0 sleep_delay = 2 - car_id = args[0] - is_wake_command = len(args) >= 2 and args[1] == "wake_up" - is_energysite_command = kwargs.get("product_type") == TESLA_PRODUCT_TYPE_ENERGY_SITES + car_id = "" + is_wake_command = False + is_energysite_command = False + if wrapped.__name__ == "api": + car_id = kwargs.get("vehicle_id", "") + else: + car_id = args[0] if not kwargs.get("vehicle_id") else kwargs.get("vehicle_id") + is_wake_command = len(args) >= 2 and args[1] == "wake_up" + is_energysite_command = ( + kwargs.get("product_type") == TESLA_PRODUCT_TYPE_ENERGY_SITES + ) result = None if ( - instance.car_online.get(instance._id_to_vin(car_id)) + instance._id_to_vin(car_id) is None + or (car_id and instance.car_online.get(instance._id_to_vin(car_id))) or is_wake_command or is_energysite_command ): @@ -150,7 +169,7 @@ def valid_result(result): "Exception: %s\n%s(%s %s)", str(ex), wrapped.__name__, args, kwargs ) raise - if valid_result(result) or is_wake_command: + if valid_result(result) or is_wake_command or is_energysite_command: return result _LOGGER.debug( "wake_up needed for %s -> %s \n" @@ -285,6 +304,7 @@ def __init__( self.energysites = {} self.__id_energysiteid_map = {} self.__energysiteid_id_map = {} + self.endpoints = {} async def connect( self, @@ -441,14 +461,14 @@ def register_websocket_callback(self, callback) -> int: @backoff.on_exception(min_expo, httpx.RequestError, max_time=10, logger=__name__) async def get_vehicles(self): """Get vehicles json from TeslaAPI.""" - return (await self.__connection.get("vehicles"))["response"] + return (await self.api("VEHICLE_LIST"))["response"] @backoff.on_exception(min_expo, httpx.RequestError, max_time=10, logger=__name__) async def get_energysites(self): """Get energy sites json from TeslaAPI.""" return [ p - for p in (await self.__connection.get("products"))["response"] + for p in (await self.api("PRODUCT_LIST"))["response"] if p.get("resource_type") == "solar" ] @@ -556,7 +576,9 @@ async def vehicle_data_request(self, car_id, name, wake_if_asleep=False): car_id = self._update_id(car_id) return ( await self.get( - car_id, f"vehicle_data/{name}", wake_if_asleep=wake_if_asleep, + car_id, + f"vehicle_data/{name}", + wake_if_asleep=wake_if_asleep, ) )["response"] @@ -578,6 +600,8 @@ async def command( ): """Post name command to the car_id. + This will be deprecated. Use self.api instead. + Parameters ---------- car_id : string @@ -736,7 +760,8 @@ def _calculate_next_interval(vin: Text) -> int: vin[-5:], sleep_interval, round( - sleep_interval + self._last_update_time[vin] - cur_time, 2, + sleep_interval + self._last_update_time[vin] - cur_time, + 2, ), ) return sleep_interval @@ -751,9 +776,9 @@ async def _get_and_process_car_data(vin: Text) -> None: async with self.__lock[vin]: _LOGGER.debug("Updating %s", vin[-5:]) try: - data = await self.get( - self.__vin_id_map[vin], - "vehicle_data", + data = await self.api( + "VEHICLE_DATA", + path_vars={"vehicle_id": self.__vin_id_map[vin]}, wake_if_asleep=wake_if_asleep, ) except TeslaException: @@ -802,9 +827,9 @@ async def _get_and_process_energysite_data(energysite_id: Text) -> None: async with self.__lock[energysite_id]: _LOGGER.debug("Updating %s", energysite_id) try: - data = await self.get( - energysite_id, - "live_status", + data = await self.api( + "SITE_DATA", + path_vars={"site_id": energysite_id}, wake_if_asleep=wake_if_asleep, product_type=TESLA_PRODUCT_TYPE_ENERGY_SITES, ) @@ -841,9 +866,9 @@ async def _get_and_process_energysite_data(energysite_id: Text) -> None: tasks = [] for vin, online in self.car_online.items(): # If specific car_id provided, only update match - if (car_vin and car_vin != vin) or (vin and self.car_state[vin].get( - "in_service" - )): + if (car_vin and car_vin != vin) or ( + vin and self.car_state[vin].get("in_service") + ): continue async with self.__lock[vin]: car_state = self.car_state[vin].get("state") @@ -1100,3 +1125,58 @@ def _process_websocket_disconnect(self, data): vehicle_id = int(data["tag"]) vin = self.__vehicle_id_vin_map[vehicle_id] _LOGGER.debug("Disconnected %s from websocket", vin[-5:]) + + @wake_up + async def api( + self, + name: str, + path_vars=None, + wake_if_asleep: bool = False, # pylint: disable=W0613 + **kwargs, + ): + """Perform api request for given endpoint name, with keyword arguments as parameters. + + Code from https://github.com/tdorssers/TeslaPy/blob/master/teslapy/__init__.py#L242-L277 under MIT + + Args + name (str): Endpoint name, e.g., STATUS + path_vars (dict, optional): Path variables to be replaced. Defaults to None. + wake_if_asleep (bool, optional): Whether to wake up any sleeping cars to update state. Defaults to False. + + Raises + ValueError: If endpoint name is not found + NotImplementedError: Endpoint method not implemented + ValueError: Path variables missing + + Returns + dict: Json dictionary response from api. + + """ + path_vars = path_vars or {} + # Load API endpoints once + if not self.endpoints: + try: + data = pkgutil.get_data(__name__, "endpoints.json") + self.endpoints = json.loads(data.decode()) + _LOGGER.debug("%d endpoints loaded", len(self.endpoints)) + except (IOError, ValueError): + _LOGGER.error("No endpoints loaded") + # Lookup endpoint name + try: + endpoint = self.endpoints[name] + except KeyError as ex: + raise ValueError("Unknown endpoint name " + name) from ex + # Only JSON is supported + if endpoint.get("CONTENT", "JSON") != "JSON" or name == "STATUS": + raise NotImplementedError(f"Endpoint {name} not implemented") + # Substitute path variables in URI + try: + uri = endpoint["URI"].format(**path_vars) + except KeyError as ex: + raise ValueError(f"{name} requires path variable {ex}") from ex + # Perform request using given keyword arguments as parameters + if endpoint["TYPE"] == "GET": + return await self.__connection.post("", method="get", data=kwargs, url=uri) + return await self.__connection.post( + "", method=endpoint["TYPE"].lower(), data=kwargs, url=uri + ) diff --git a/teslajsonpy/endpoints.json b/teslajsonpy/endpoints.json new file mode 100644 index 00000000..667f72ef --- /dev/null +++ b/teslajsonpy/endpoints.json @@ -0,0 +1,1353 @@ +{ + "STATUS": { + "TYPE": "GET", + "URI": "status", + "AUTH": false + }, + "PRODUCT_LIST": { + "TYPE": "GET", + "URI": "api/1/products", + "AUTH": true + }, + "VEHICLE_LIST": { + "TYPE": "GET", + "URI": "api/1/vehicles", + "AUTH": true + }, + "VEHICLE_ORDER_LIST": { + "TYPE": "GET", + "URI": "api/1/users/orders", + "AUTH": true + }, + "VEHICLE_SUMMARY": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}", + "AUTH": true + }, + "VEHICLE_DATA_LEGACY": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/data", + "AUTH": true + }, + "VEHICLE_DATA": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/vehicle_data", + "AUTH": true + }, + "VEHICLE_SERVICE_DATA": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/service_data", + "AUTH": true + }, + "NEARBY_CHARGING_SITES": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/nearby_charging_sites", + "AUTH": true + }, + "WAKE_UP": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/wake_up", + "AUTH": true + }, + "UNLOCK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/door_unlock", + "AUTH": true + }, + "LOCK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/door_lock", + "AUTH": true + }, + "HONK_HORN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/honk_horn", + "AUTH": true + }, + "FLASH_LIGHTS": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/flash_lights", + "AUTH": true + }, + "CLIMATE_ON": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/auto_conditioning_start", + "AUTH": true + }, + "CLIMATE_OFF": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/auto_conditioning_stop", + "AUTH": true + }, + "MAX_DEFROST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_preconditioning_max", + "AUTH": true + }, + "CHANGE_CLIMATE_TEMPERATURE_SETTING": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_temps", + "AUTH": true + }, + "HVAC_BIOWEAPON_MODE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_bioweapon_mode", + "AUTH": true + }, + "SCHEDULED_DEPARTURE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_scheduled_departure", + "AUTH": true + }, + "SCHEDULED_CHARGING": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_scheduled_charging", + "AUTH": true + }, + "CHARGING_AMPS": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_charging_amps", + "AUTH": true + }, + "CHANGE_CHARGE_LIMIT": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_charge_limit", + "AUTH": true + }, + "CHANGE_CHARGE_MAX": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_max_range", + "AUTH": true + }, + "CHANGE_CHARGE_STANDARD": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_standard", + "AUTH": true + }, + "CHANGE_SUNROOF_STATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/sun_roof_control", + "AUTH": true + }, + "WINDOW_CONTROL": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/window_control", + "AUTH": true + }, + "ACTUATE_TRUNK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/actuate_trunk", + "AUTH": true + }, + "REMOTE_START": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_start_drive", + "AUTH": true + }, + "TRIGGER_HOMELINK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/trigger_homelink", + "AUTH": true + }, + "CHARGE_PORT_DOOR_OPEN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_port_door_open", + "AUTH": true + }, + "CHARGE_PORT_DOOR_CLOSE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_port_door_close", + "AUTH": true + }, + "START_CHARGE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_start", + "AUTH": true + }, + "STOP_CHARGE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_stop", + "AUTH": true + }, + "MEDIA_TOGGLE_PLAYBACK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_toggle_playback", + "AUTH": true + }, + "MEDIA_NEXT_TRACK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_next_track", + "AUTH": true + }, + "MEDIA_PREVIOUS_TRACK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_prev_track", + "AUTH": true + }, + "MEDIA_NEXT_FAVORITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_next_fav", + "AUTH": true + }, + "MEDIA_PREVIOUS_FAVORITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_prev_fav", + "AUTH": true + }, + "MEDIA_VOLUME_UP": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_volume_up", + "AUTH": true + }, + "MEDIA_VOLUME_DOWN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_volume_down", + "AUTH": true + }, + "SPLUNK_TELEMETRY": { + "TYPE": "POST", + "URI": "api/1/logs", + "AUTH": true + }, + "APP_FEEDBACK_ENTITLEMENTS": { + "TYPE": "GET", + "URI": "api/1/diagnostics", + "AUTH": true + }, + "APP_FEEDBACK_LOGS": { + "TYPE": "POST", + "URI": "api/1/reports", + "AUTH": true + }, + "APP_FEEDBACK_METADATA": { + "TYPE": "POST", + "URI": "api/1/diagnostics", + "AUTH": true + }, + "RETRIEVE_NOTIFICATION_PREFERENCES": { + "TYPE": "GET", + "URI": "api/1/notification_preferences", + "AUTH": true + }, + "SEND_NOTIFICATION_PREFERENCES": { + "TYPE": "POST", + "URI": "api/1/notification_preferences", + "AUTH": true + }, + "RETRIEVE_NOTIFICATION_SUBSCRIPTIONS": { + "TYPE": "GET", + "URI": "api/1/subscriptions", + "AUTH": true + }, + "SEND_NOTIFICATION_SUBSCRIPTIONS": { + "TYPE": "POST", + "URI": "api/1/subscriptions", + "AUTH": true + }, + "DEACTIVATE_DEVICE_TOKEN": { + "TYPE": "POST", + "URI": "api/1/device/{device_token}/deactivate", + "AUTH": true + }, + "CALENDAR_SYNC": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/upcoming_calendar_entries", + "AUTH": true + }, + "SET_VALET_MODE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_valet_mode", + "AUTH": true + }, + "RESET_VALET_PIN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/reset_valet_pin", + "AUTH": true + }, + "SPEED_LIMIT_ACTIVATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_activate", + "AUTH": true + }, + "SPEED_LIMIT_DEACTIVATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_deactivate", + "AUTH": true + }, + "SPEED_LIMIT_SET_LIMIT": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_set_limit", + "AUTH": true + }, + "SPEED_LIMIT_CLEAR_PIN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_clear_pin", + "AUTH": true + }, + "SCHEDULE_SOFTWARE_UPDATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/schedule_software_update", + "AUTH": true + }, + "CANCEL_SOFTWARE_UPDATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/cancel_software_update", + "AUTH": true + }, + "SET_SENTRY_MODE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_sentry_mode", + "AUTH": true + }, + "POWERWALL_ORDER_SESSION_DATA": { + "TYPE": "GET", + "URI": "api/1/users/powerwall_order_entry_data", + "AUTH": true + }, + "POWERWALL_ORDER_PAGE": { + "TYPE": "GET", + "URI": "powerwall_order_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "ONBOARDING_EXPERIENCE": { + "TYPE": "GET", + "URI": "api/1/users/onboarding_data", + "AUTH": true + }, + "ONBOARDING_EXPERIENCE_PAGE": { + "TYPE": "GET", + "URI": "onboarding_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "GET_UPCOMING_SERVICE_VISIT_DATA": { + "TYPE": "GET", + "URI": "api/1/users/service_scheduling_data", + "AUTH": true + }, + "GET_OWNERSHIP_XP_CONFIG": { + "TYPE": "GET", + "URI": "api/1/users/app_config", + "AUTH": true + }, + "REFERRAL_DATA": { + "TYPE": "GET", + "URI": "api/1/users/referral_data", + "AUTH": true + }, + "REFERRAL_PAGE": { + "TYPE": "GET", + "URI": "referral_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "ROADSIDE_ASSISTANCE_DATA": { + "TYPE": "GET", + "URI": "api/1/users/roadside_assistance_data", + "AUTH": true + }, + "ROADSIDE_ASSISTANCE_PAGE": { + "TYPE": "GET", + "URI": "roadside_assistance_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "UPGRADE_ELIGIBILITY": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/eligible_upgrades", + "AUTH": true + }, + "UPGRADES_PAGE": { + "TYPE": "GET", + "URI": "upgrades_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "MESSAGE_CENTER_MESSAGE_COUNT": { + "TYPE": "GET", + "URI": "api/1/messages/count", + "AUTH": true + }, + "MESSAGE_CENTER_MESSAGE_LIST": { + "TYPE": "GET", + "URI": "api/1/messages", + "AUTH": true + }, + "MESSAGE_CENTER_MESSAGE": { + "TYPE": "GET", + "URI": "api/1/messages/{message_id}", + "AUTH": true + }, + "MESSAGE_CENTER_COUNTS": { + "TYPE": "GET", + "URI": "api/1/messages/count", + "AUTH": true + }, + "MESSAGE_CENTER_MESSAGE_ACTION_UPDATE": { + "TYPE": "POST", + "URI": "api/1/messages/{message_id}/actions", + "AUTH": true + }, + "MESSAGE_CENTER_CTA_PAGE": { + "TYPE": "GET", + "URI": "messages_cta_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "SEND_DEVICE_KEY": { + "TYPE": "POST", + "URI": "api/1/users/keys", + "AUTH": true + }, + "BATTERY_SUMMARY": { + "TYPE": "GET", + "URI": "api/1/powerwalls/{battery_id}/status", + "AUTH": true + }, + "BATTERY_DATA": { + "TYPE": "GET", + "URI": "api/1/powerwalls/{battery_id}", + "AUTH": true + }, + "BATTERY_POWER_TIMESERIES_DATA": { + "TYPE": "GET", + "URI": "api/1/powerwalls/{battery_id}/powerhistory", + "AUTH": true + }, + "BATTERY_ENERGY_TIMESERIES_DATA": { + "TYPE": "GET", + "URI": "api/1/powerwalls/{battery_id}/energyhistory", + "AUTH": true + }, + "BATTERY_BACKUP_RESERVE": { + "TYPE": "POST", + "URI": "api/1/powerwalls/{battery_id}/backup", + "AUTH": true + }, + "BATTERY_SITE_NAME": { + "TYPE": "POST", + "URI": "api/1/powerwalls/{battery_id}/site_name", + "AUTH": true + }, + "BATTERY_OPERATION_MODE": { + "TYPE": "POST", + "URI": "api/1/powerwalls/{battery_id}/operation", + "AUTH": true + }, + "SITE_SUMMARY": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/site_status", + "AUTH": true + }, + "SITE_DATA": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/live_status", + "AUTH": true + }, + "SITE_CONFIG": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/site_info", + "AUTH": true + }, + "SITE_TARIFFS": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/tariff_rates", + "AUTH": true + }, + "HISTORY_DATA": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/history", + "AUTH": true + }, + "CALENDAR_HISTORY_DATA": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/calendar_history", + "AUTH": true + }, + "SOLAR_SAVINGS_FORECAST": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/savings_forecast", + "AUTH": true + }, + "ENERGY_SITE_BACKUP_TIME_REMAINING": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/backup_time_remaining", + "AUTH": true + }, + "ENERGY_SITE_PROGRAMS": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/programs", + "AUTH": true + }, + "ENERGY_SITE_TELEMETRY_HISTORY": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/telemetry_history", + "AUTH": true + }, + "BACKUP_RESERVE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/backup", + "AUTH": true + }, + "OFF_GRID_VEHICLE_CHARGING_RESERVE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/off_grid_vehicle_charging_reserve", + "AUTH": true + }, + "SITE_NAME": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/site_name", + "AUTH": true + }, + "OPERATION_MODE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/operation", + "AUTH": true + }, + "TIME_OF_USE_SETTINGS": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/time_of_use_settings", + "AUTH": true + }, + "STORM_MODE_SETTINGS": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/storm_mode", + "AUTH": true + }, + "ENERGY_SITE_COMMAND": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/command", + "AUTH": true + }, + "ENERGY_SITE_ENROLL_PROGRAM": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/program", + "AUTH": true + }, + "ENERGY_SITE_OPT_EVENT": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/event", + "AUTH": true + }, + "ENERGY_SITE_PREFERENCE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/preference", + "AUTH": true + }, + "SEND_NOTIFICATION_CONFIRMATION": { + "TYPE": "POST", + "URI": "api/1/notification_confirmations", + "AUTH": true + }, + "SEND_TO_VEHICLE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/share", + "AUTH": true + }, + "REMOTE_SEAT_HEATER_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_seat_heater_request", + "AUTH": true + }, + "REMOTE_STEERING_WHEEL_HEATER_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_steering_wheel_heater_request", + "AUTH": true + }, + "TRIGGER_VEHICLE_SCREENSHOT": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/screenshot", + "AUTH": true + }, + "HERMES_AUTHORIZATION": { + "TYPE": "POST", + "URI": "api/1/users/jwt/hermes", + "AUTH": true + }, + "HERMES_VEHICLE_AUTHORIZATION": { + "TYPE": "POST", + "URI": "api/1/vehicles/{id}/jwt/hermes", + "AUTH": true + }, + "STATIC_SUPERCHARGER_FILE": { + "TYPE": "GET", + "URI": "static/superchargers/{file_path}", + "AUTH": true + }, + "STATIC_CHARGER_FILE": { + "TYPE": "GET", + "URI": "static/chargers/{file_path}", + "AUTH": true + }, + "PLAN_TRIP": { + "TYPE": "POST", + "URI": "api/1/vehicles/plan_trip", + "AUTH": true + }, + "PLACE_SUGGESTIONS": { + "TYPE": "POST", + "URI": "api/1/vehicles/place_suggestions", + "AUTH": true + }, + "DRIVING_PLAN": { + "TYPE": "POST", + "URI": "api/1/vehicles/driving_plan", + "AUTH": true + }, + "REVERSE_GEOCODING": { + "TYPE": "GET", + "URI": "maps/reverse_geocoding/v3/", + "AUTH": true + }, + "USER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/user", + "AUTH": true + }, + "OWNERSHIP_TRANSLATIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/static/protected/translations/{path}", + "AUTH": true + }, + "ROADSIDE_INCIDENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/incidents", + "AUTH": true + }, + "ROADSIDE_CREATE_INCIDENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/roadside/incidents", + "AUTH": true + }, + "ROADSIDE_CANCEL_INCIDENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/roadside/incidents/{incidentsId}", + "AUTH": true + }, + "ROADSIDE_WARRANTY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/warranty", + "AUTH": true + }, + "ROADSIDE_LOCATIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/locations", + "AUTH": true + }, + "ROADSIDE_COUNTRIES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/countries", + "AUTH": true + }, + "SERVICE_GET_SERVICE_APPOINTMENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/service-appointments", + "AUTH": true + }, + "SERVICE_TRACKER_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_MOBILE_OPEN_APPOINTMENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/mobile/slots", + "AUTH": true + }, + "SERVICE_CENTER_OPEN_APPOINTMENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/center/slots", + "AUTH": true + }, + "SERVICE_SAVE_CENTER_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/center", + "AUTH": true + }, + "SERVICE_CREATE_MOBILE_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/mobile", + "AUTH": true + }, + "SERVICE_CANCEL_CENTER_APPOINTMENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/service/center/{appointmentId}", + "AUTH": true + }, + "SERVICE_CANCEL_MOBILE_APPOINTMENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/service/mobile/{appointmentId}", + "AUTH": true + }, + "SERVICE_UPDATE_MOBILE_APPOINTMENT": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/service/mobile/{appointmentId}", + "AUTH": true + }, + "SERVICE_SWITCH_TO_CENTER_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/mobile/{appointmentId}/convert-to-center", + "AUTH": true + }, + "SERVICE_SWITCH_TO_MOBILE_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/center/{appointmentId}/convert-to-mobile", + "AUTH": true + }, + "SERVICE_MOBILE_APPOINTMENT_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/mobile/{appointmentId}", + "AUTH": true + }, + "SERVICE_CENTER_APPOINTMENT_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/center/{appointmentId}", + "AUTH": true + }, + "SERVICE_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/history", + "AUTH": true + }, + "SERVICE_LOCATIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/center/locations", + "AUTH": true + }, + "SERVICE_LOCATIONS_BY_TRT_ID": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/center/locations-by-trtid", + "AUTH": true + }, + "SERVICE_MOBILE_ISSUES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/mobile-service-issues", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_SERVICE_TRACKER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/mobile-app-service-tracker", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_ALLOW_FILE_UPLOAD": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/service-scheduling-allow-file-upload", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_MOBILE_SERVICE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/show-mobile-service", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_MACGYVER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/tao-4109-use-macgyver-mobile-app", + "AUTH": true + }, + "SERVICE_UPLOAD_FILE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/files", + "AUTH": true + }, + "SERVICE_DELETE_UPLOADED_FILE": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/files/{uuid}", + "AUTH": true + }, + "SERVICE_UPDATE_FILE_METADATA": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/files/{uuid}/metadata", + "AUTH": true + }, + "SERVICE_GET_FILE_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/files/metadata", + "AUTH": true + }, + "SERVICE_GET_FILE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/files/{uuid}", + "AUTH": true + }, + "SERVICE_GET_APPOINTMENT_INVOICES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/invoices", + "AUTH": true + }, + "SERVICE_GET_ESTIMATE_APPROVAL_STATUS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/estimate-status", + "AUTH": true + }, + "SERVICE_GET_ESTIMATE_COST_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/invoices/{invoiceId}", + "AUTH": true + }, + "SERVICE_APPROVE_ESTIMATE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/estimate-status", + "AUTH": true + }, + "SERVICE_GET_FINAL_INVOICE_AMOUNT_DUE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/amount-due", + "AUTH": true + }, + "SERVICE_MACGYVER_ALERTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/macgyver/alerts", + "AUTH": true + }, + "SERVICE_MACGYVER_OUTSTANDING_WORK": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/macgyver/categories", + "AUTH": true + }, + "SERVICE_ACTIVITY_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/macgyver/activity-info/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_MACGYVER_POST_CUSTOMER_ANSWERS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/macgyver/customer-answers", + "AUTH": true + }, + "SERVICE_MACGYVER_DISMISS_CUSTOMER_ANSWERS": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/macgyver/customer-answers", + "AUTH": true + }, + "SERVICE_MACGYVER_SERVICE_TYPE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/macgyver/service-type", + "AUTH": true + }, + "SERVICE_ACCEPT_LOANER_AGREEMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/loaner/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/payment/create-offline-order", + "AUTH": true + }, + "SERVICE_COMPLETE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/payment/complete-offline-order", + "AUTH": true + }, + "ENERGY_OWNERSHIP_GET_TOGGLES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy/feature-flags", + "AUTH": true + }, + "ENERGY_SERVICE_GET_SITE_INFORMATION": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-service/site-information", + "AUTH": true + }, + "ENERGY_SERVICE_GET_SERVICE_CASES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-service/appointments", + "AUTH": true + }, + "ENERGY_SERVICE_POST_SERVICE_CASE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy-service/appointments", + "AUTH": true + }, + "ENERGY_SERVICE_GET_APPOINTMENT_SUGGESTIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-service/appointment-suggestions", + "AUTH": true + }, + "ENERGY_SERVICE_CANCEL_SERVICE_CASE": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/energy-service/service-case", + "AUTH": true + }, + "ENERGY_SERVICE_CANCEL_APPOINTMENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/energy-service/appointments", + "AUTH": true + }, + "ENERGY_DOCUMENTS_GET_DOCUMENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-documents/documents", + "AUTH": true + }, + "ENERGY_DOCUMENTS_DOWNLOAD_DOCUMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-documents/documents/{documentId}", + "AUTH": true + }, + "ENERGY_GET_TROUBLESHOOTING_GUIDE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-service/troubleshooting/{troubleshootingFlow}", + "AUTH": true + }, + "LOOTBOX_USER_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals", + "AUTH": true + }, + "LOOTBOX_GET_ONBOARDING_COPY": { + "TYPE": "GET", + "URI": "mobile-app/referrals/getOnboardingCopy", + "AUTH": true + }, + "LOOTBOX_PAST_REFERRAL_DATA": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/past-referrals", + "AUTH": true + }, + "REFERRAL_GET_USER_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/user-info", + "AUTH": true + }, + "REFERRAL_GET_PRODUCT_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/product-info", + "AUTH": true + }, + "REFERRAL_GET_CONTACT_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/contact-list", + "AUTH": true + }, + "REFERRAL_POST_CONTACT_LIST": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/referrals/contact-list", + "AUTH": true + }, + "REFERRAL_GET_CREDIT_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/credit-history", + "AUTH": true + }, + "REFERRAL_GET_PAST_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/past-referral-history", + "AUTH": true + }, + "REFERRAL_GET_PAST_HISTORY_COUNT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/past-referral-history/count", + "AUTH": true + }, + "REFERRAL_GET_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/tao-69420-treasure", + "AUTH": true + }, + "REFERRAL_GET_TERMS_AND_CONDITIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/terms-conditions", + "AUTH": true + }, + "UPGRADES_GET_ELIGIBLE_UPGRADES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/upgrades/eligible", + "AUTH": true + }, + "UPGRADES_GET_PURCHASED_UPGRADES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/upgrades/purchased", + "AUTH": true + }, + "UPGRADES_SUBMIT_REFUND": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/refunds", + "AUTH": true + }, + "UPGRADES_POST_PAYMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/payment", + "AUTH": true + }, + "USER_ACCOUNT_GET_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/account/details", + "AUTH": true + }, + "USER_ACCOUNT_PUT_DETAILS": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/account/details", + "AUTH": true + }, + "USER_ACCOUNT_UPLOAD_PROFILE_PICTURE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/account/profile-pic", + "AUTH": true + }, + "USER_ACCOUNT_DOWNLOAD_PROFILE_PICTURE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/account/profile-pic", + "AUTH": true + }, + "UPGRADES_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/payment/offline-order", + "AUTH": true + }, + "UPGRADES_COMPLETE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/payment/offline-purchase-complete", + "AUTH": true + }, + "SUBSCRIPTIONS_GET_ELIGIBLE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions", + "AUTH": true + }, + "SUBSCRIPTIONS_GET_PURCHASED_SUBSCRIPTIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/purchased", + "AUTH": true + }, + "SUBSCRIPTIONS_CREATE_OFFLINE_ORDER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/offline-order", + "AUTH": true + }, + "SUBSCRIPTIONS_POST_CREATE_OFFLINE_ORDER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/offline-order", + "AUTH": true + }, + "GET_WALLET_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/enable-subscriptions-wallet-channel", + "AUTH": true + }, + "SUBSCRIPTIONS_PURCHASE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/subscriptions", + "AUTH": true + }, + "MANAGE_GET_SUBSCRIPTION_INVOICES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/invoices", + "AUTH": true + }, + "MANAGE_PATCH_AUTO_RENEW_SUBSCRIPTIONS": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/subscriptions", + "AUTH": true + }, + "MANAGE_GET_BILL_ME_LATER_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/bill-me-later/pending-orders", + "AUTH": true + }, + "MANAGE_COMPLETE_BILL_ME_LATER_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/bill-me-later/purchase-complete", + "AUTH": true + }, + "MANAGE_CANCEL_BILL_ME_LATER_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/bill-me-later/cancel", + "AUTH": true + }, + "MANAGE_UPGRADE_BILL_ME_LATER_GET_OFFLINE_TOKEN": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/bill-me-later/token", + "AUTH": true + }, + "UPGRADES_SUBSCRIPTIONS_SHARED_BILLING_ADDRESS_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/billing-address/feature-flag/TAO-8065-in-app-BillingBlock-Enable", + "AUTH": true + }, + "BILLING_ADDRESS_FORM_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/billing-address/feature-flag/tao-8202-ownership-mobile-app-billing-address", + "AUTH": true + }, + "VIDEO_GUIDES_GET_VIDEO_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/video-guides", + "AUTH": true + }, + "PAYMENTS_GET_SIGNED_USER_TOKEN": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/payments/signed-user-token", + "AUTH": true + }, + "PAYMENTS_POST_SIGNED_USER_TOKEN": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/payments/signed-user-token", + "AUTH": true + }, + "PAYMENTS_GET_INSTRUMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/payments/instrument", + "AUTH": true + }, + "PAYMENTS_GET_BILLING_ADDRESS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/billing-address", + "AUTH": true + }, + "PAYMENTS_UPDATE_BILLING_ADDRESS": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/billing-address", + "AUTH": true + }, + "DOCUMENTS_DOWNLOAD_INVOICE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/documents/invoices/{invoiceId}", + "AUTH": true + }, + "SERVICE_MESSAGES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/messages/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_SEND_MESSAGE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/messages/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_MESSAGES_MARK_READ": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/service/messages/{serviceVisitID}", + "AUTH": true + }, + "COMMERCE_CATEGORIES": { + "TYPE": "GET", + "URI": "commerce-api/categories/v1{locale}", + "AUTH": true + }, + "COMMERCE_RECOMMENDATIONS_CATEGORIES": { + "TYPE": "POST", + "URI": "commerce-api/recommendations/categories/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_ADDRESS": { + "TYPE": "GET", + "URI": "commerce-api/addresses/v1{locale}", + "AUTH": true + }, + "COMMERCE_ADDRESS": { + "TYPE": "POST", + "URI": "commerce-api/addresses/v1{locale}", + "AUTH": true + }, + "COMMERCE_CAPTURE": { + "TYPE": "POST", + "URI": "commerce-api/purchases/v1{locale}", + "AUTH": true + }, + "COMMERCE_PROCESSPAYMENT": { + "TYPE": "POST", + "URI": "commerce-api/purchases/{purchaseNumber}/processpayment/v1{locale}", + "AUTH": true + }, + "COMMERCE_CART_UPDATE": { + "TYPE": "PUT", + "URI": "commerce-api/carts/{cartId}/items/{lineItemId}/v1{locale}", + "AUTH": true + }, + "COMMERCE_CART_DELETE": { + "TYPE": "DELETE", + "URI": "commerce-api/carts/{cartId}/items/{lineItemId}/v1{locale}", + "AUTH": true + }, + "COMMERCE_ADD_CART": { + "TYPE": "POST", + "URI": "commerce-api/carts/items/v1{locale}", + "AUTH": true + }, + "COMMERCE_CLEAR_CART": { + "TYPE": "DELETE", + "URI": "commerce-api/carts/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_CART": { + "TYPE": "GET", + "URI": "commerce-api/carts/v1{locale}", + "AUTH": true + }, + "COMMERCE_INVENTORY": { + "TYPE": "POST", + "URI": "commerce-api/inventory/v2{locale}", + "AUTH": true + }, + "COMMERCE_ITEM": { + "TYPE": "POST", + "URI": "commerce-api/items/v1{locale}", + "AUTH": true + }, + "COMMERCE_TOKEN": { + "TYPE": "POST", + "URI": "commerce-api/tokens/v1{locale}", + "AUTH": true + }, + "COMMERCE_ADDRESS_VALIDATION": { + "TYPE": "POST", + "URI": "commerce-api/addresses/validations/v1{locale}", + "AUTH": true + }, + "COMMERCE_GEOGRAPHIES": { + "TYPE": "GET", + "URI": "commerce-api/geographies/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_STORE_INFO": { + "TYPE": "GET", + "URI": "commerce-api/storeconfigurations/v1{locale}", + "AUTH": true + }, + "COMMERCE_PURCHASE_HISTORY": { + "TYPE": "GET", + "URI": "commerce-api/purchases/v1{locale}", + "AUTH": true + }, + "COMMERCE_PURCHASE_BY_ORDERNUMBER": { + "TYPE": "GET", + "URI": "commerce-api/purchases/{orderNumber}/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_VEHICLES": { + "TYPE": "GET", + "URI": "commerce-api/vehicles/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_VEHICLES": { + "TYPE": "POST", + "URI": "commerce-api/vehicles/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_SERVICECENTERS": { + "TYPE": "GET", + "URI": "commerce-api/servicecenters/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_SERVICECENTERS": { + "TYPE": "POST", + "URI": "commerce-api/servicecenters/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_CANCELORDER": { + "TYPE": "POST", + "URI": "commerce-api/cancellation/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_RETURNORDER": { + "TYPE": "POST", + "URI": "commerce-api/returns/v1{locale}", + "AUTH": true + }, + "MATTERMOST": { + "TYPE": "POST", + "URI": "Just a placeholder", + "AUTH": true + }, + "SAFETY_RATING_GET_ELIGIBLE_FOR_TELEMATICS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance/eligible-for-telematics", + "AUTH": true + }, + "SAFETY_RATING_GET_DAILY_BREAKDOWN": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance/daily-breakdown", + "AUTH": true + }, + "SAFETY_RATING_GET_TRIPS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance/trips", + "AUTH": true + }, + "SAFETY_RATING_GET_ESTIMATED_SAFETY_SCORE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance/calculate-safety-rating", + "AUTH": true + }, + "COMMERCE_POST_INVOICE": { + "TYPE": "POST", + "URI": "commerce-api/purchases/invoices/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_CHECKOUT_INVOICE": { + "TYPE": "POST", + "URI": "commerce-api/checkout/invoices/v1{locale}", + "AUTH": true + }, + "CHARGING_BALANCE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/balance", + "AUTH": true + }, + "CHARGING_BALANCE_CHARGE_TYPE_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/tao-9296-filter-by-charge-type", + "AUTH": true + }, + "CHARGING_BALANCE_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/charging/payment", + "AUTH": true + }, + "CHARGING_BALANCE_PAYMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/charging/payment/complete", + "AUTH": true + }, + "CHARGING_BALANCE_ZERO_DOLLAR_TX": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/signed-token", + "AUTH": true + }, + "CHARGING_BALANCE_GET_IS_BLOCKED": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging-cn/supercharger-status", + "AUTH": true + }, + "CHARGING_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/history", + "AUTH": true + }, + "CHARGING_HISTORY_VEHICLES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/vehicles", + "AUTH": true + }, + "CHARGING_HISTORY_VEHICLE_IMAGES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/vehicle-images", + "AUTH": true + }, + "DOWNLOAD_CHARGING_INVOICE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/invoice/{uuid}", + "AUTH": true + }, + "CHARGING_DOWNLOAD_CSV": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/export", + "AUTH": true + }, + "CHARGING_GET_BILLING_ADDRESS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/billing-address", + "AUTH": true + }, + "CHARGING_SET_BILLING_ADDRESS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/charging/billing-address", + "AUTH": true + }, + "FEATURE_CONFIG": { + "TYPE": "GET", + "URI": "api/1/users/feature_config", + "AUTH": true + } + } \ No newline at end of file diff --git a/teslajsonpy/homeassistant/charger.py b/teslajsonpy/homeassistant/charger.py index fd0be5d4..accb3377 100644 --- a/teslajsonpy/homeassistant/charger.py +++ b/teslajsonpy/homeassistant/charger.py @@ -62,8 +62,8 @@ def refresh(self) -> None: async def start_charge(self): """Start charging the Tesla Vehicle.""" if not self.__charger_state: - data = await self._controller.command( - self._id, "charge_start", wake_if_asleep=True + data = await self._controller.api( + "START_CHARGE", path_vars={"vehicle_id": self._id}, wake_if_asleep=True ) if data and data["response"]["result"]: self.__charger_state = True @@ -72,8 +72,8 @@ async def start_charge(self): async def stop_charge(self): """Stop charging the Tesla Vehicle.""" if self.__charger_state: - data = await self._controller.command( - self._id, "charge_stop", wake_if_asleep=True + data = await self._controller.api( + "STOP_CHARGE", path_vars={"vehicle_id": self._id}, wake_if_asleep=True ) if data and data["response"]["result"]: self.__charger_state = False @@ -123,8 +123,8 @@ def refresh(self) -> None: async def set_max(self): """Set the charger to max range for trips.""" if not self.__maxrange_state: - data = await self._controller.command( - self._id, "charge_max_range", wake_if_asleep=True + data = await self._controller.api( + "CHANGE_CHARGE_MAX", path_vars={"vehicle_id": self._id}, wake_if_asleep=True ) if data and data["response"]["result"]: self.__maxrange_state = True @@ -133,8 +133,8 @@ async def set_max(self): async def set_standard(self): """Set the charger to standard range for daily commute.""" if self.__maxrange_state: - data = await self._controller.command( - self._id, "charge_standard", wake_if_asleep=True + data = await self._controller.api( + "CHANGE_CHARGE_STANDARD", path_vars={"vehicle_id": self._id}, wake_if_asleep=True ) if data and data["response"]["result"]: self.__maxrange_state = False diff --git a/teslajsonpy/homeassistant/climate.py b/teslajsonpy/homeassistant/climate.py index 487546cd..b4e75452 100644 --- a/teslajsonpy/homeassistant/climate.py +++ b/teslajsonpy/homeassistant/climate.py @@ -115,10 +115,11 @@ async def set_temperature(self, temp): """Set both the driver and passenger temperature to temp.""" temp = round(temp, 1) self.__manual_update_time = time.time() - data = await self._controller.command( - self._id, - "set_temps", - {"driver_temp": temp, "passenger_temp": temp}, + data = await self._controller.api( + "CHANGE_CLIMATE_TEMPERATURE_SETTING", + path_vars={"vehicle_id": self._id}, + driver_temp=temp, + passenger_temp=temp, wake_if_asleep=True, ) if data and data["response"]["result"]: @@ -129,15 +130,15 @@ async def set_status(self, enabled): """Enable or disable the HVAC.""" self.__manual_update_time = time.time() if enabled: - data = await self._controller.command( - self._id, "auto_conditioning_start", wake_if_asleep=True + data = await self._controller.api( + "CLIMATE_ON", path_vars={"vehicle_id": self._id}, wake_if_asleep=True ) if data and data["response"]["result"]: self.__is_auto_conditioning_on = True self.__is_climate_on = True else: - data = await self._controller.command( - self._id, "auto_conditioning_stop", wake_if_asleep=True + data = await self._controller.api( + "CLIMATE_OFF", path_vars={"vehicle_id": self._id}, wake_if_asleep=True ) if data and data["response"]["result"]: self.__is_auto_conditioning_on = False @@ -151,10 +152,10 @@ async def set_preset_mode(self, preset_mode: str) -> None: f"Preset mode '{preset_mode}' is not valid. Use {self.preset_modes}" ) self.__manual_update_time = time.time() - data = await self._controller.command( - self._id, - "set_preconditioning_max", - data={"on": preset_mode == "defrost"}, + data = await self._controller.api( + "MAX_DEFROST", + path_vars={"vehicle_id": self._id}, + on=preset_mode == "defrost", wake_if_asleep=True, ) if data and data["response"]["result"]: diff --git a/teslajsonpy/homeassistant/heated_seats.py b/teslajsonpy/homeassistant/heated_seats.py index e64bbdc6..77160986 100644 --- a/teslajsonpy/homeassistant/heated_seats.py +++ b/teslajsonpy/homeassistant/heated_seats.py @@ -75,10 +75,11 @@ def refresh(self) -> None: async def set_seat_heat_level(self, level): """Set heated seat level.""" - data = await self._controller.command( - self._id, - "remote_seat_heater_request", - data={"heater": seat_id_map[self.__seat_name], "level": level}, + data = await self._controller.api( + "REMOTE_SEAT_HEATER_REQUEST", + path_vars={"vehicle_id": self._id}, + heater=seat_id_map[self.__seat_name], + level=level, wake_if_asleep=True, ) if data and data["response"]["result"]: diff --git a/teslajsonpy/homeassistant/heated_steering_wheel.py b/teslajsonpy/homeassistant/heated_steering_wheel.py index e6152181..ef00f2e7 100644 --- a/teslajsonpy/homeassistant/heated_steering_wheel.py +++ b/teslajsonpy/homeassistant/heated_steering_wheel.py @@ -64,10 +64,10 @@ def refresh(self) -> None: async def set_steering_wheel_heat(self, value: bool): """Set heated steering wheel.""" - data = await self._controller.command( - self._id, - "remote_steering_wheel_heater_request", - data={"on": value}, + data = await self._controller.api( + "REMOTE_STEERING_WHEEL_HEATER_REQUEST", + path_vars={"vehicle_id": self._id}, + on=value, wake_if_asleep=True, ) if data and data["response"]["result"]: diff --git a/teslajsonpy/homeassistant/lock.py b/teslajsonpy/homeassistant/lock.py index 02bd85c8..721b27bb 100644 --- a/teslajsonpy/homeassistant/lock.py +++ b/teslajsonpy/homeassistant/lock.py @@ -62,8 +62,10 @@ def refresh(self) -> None: async def lock(self): """Lock the doors.""" - data = await self._controller.command( - self._id, "door_lock", wake_if_asleep=True + data = await self._controller.api( + "LOCK", + path_vars={"vehicle_id": self._id}, + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = True @@ -71,8 +73,10 @@ async def lock(self): async def unlock(self): """Unlock the doors and extend handles where applicable.""" - data = await self._controller.command( - self._id, "door_unlock", wake_if_asleep=True + data = await self._controller.api( + "UNLOCK", + path_vars={"vehicle_id": self._id}, + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = False @@ -147,8 +151,10 @@ def refresh(self) -> None: async def lock(self): """Close the charger door.""" - data = await self._controller.command( - self._id, "charge_port_door_close", wake_if_asleep=True + data = await self._controller.api( + "CHARGE_PORT_DOOR_CLOSE", + path_vars={"vehicle_id": self._id}, + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = True @@ -156,8 +162,10 @@ async def lock(self): async def unlock(self): """Open the charger door.""" - data = await self._controller.command( - self._id, "charge_port_door_open", wake_if_asleep=True + data = await self._controller.api( + "CHARGE_PORT_DOOR_OPEN", + path_vars={"vehicle_id": self._id}, + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = False diff --git a/teslajsonpy/homeassistant/sentry_mode.py b/teslajsonpy/homeassistant/sentry_mode.py index 360168cc..e92e254f 100644 --- a/teslajsonpy/homeassistant/sentry_mode.py +++ b/teslajsonpy/homeassistant/sentry_mode.py @@ -80,8 +80,11 @@ def has_battery() -> bool: async def enable_sentry_mode(self) -> None: """Enable the sentry mode.""" if self.sentry_mode_available and not self.__sentry_mode: - data = await self._controller.command( - self._id, "set_sentry_mode", {"on": True}, wake_if_asleep=True + data = await self._controller.api( + "SET_SENTRY_MODE", + path_vars={"vehicle_id": self._id}, + on=True, + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__sentry_mode = True @@ -90,8 +93,11 @@ async def enable_sentry_mode(self) -> None: async def disable_sentry_mode(self) -> None: """Disable the sentry mode.""" if self.sentry_mode_available and self.__sentry_mode: - data = await self._controller.command( - self._id, "set_sentry_mode", {"on": False}, wake_if_asleep=True + data = await self._controller.api( + "SET_SENTRY_MODE", + path_vars={"vehicle_id": self._id}, + on=False, + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__sentry_mode = False diff --git a/teslajsonpy/homeassistant/trunk.py b/teslajsonpy/homeassistant/trunk.py index 4655b528..1794ff13 100644 --- a/teslajsonpy/homeassistant/trunk.py +++ b/teslajsonpy/homeassistant/trunk.py @@ -56,8 +56,11 @@ def is_locked(self): async def unlock(self): """Open the rear trunk.""" if self.is_locked(): - data = await self._controller.command( - self._id, "actuate_trunk", {"which_trunk": "rear"}, wake_if_asleep=True + data = await self._controller.api( + "ACTUATE_TRUNK", + path_vars={"vehicle_id": self._id}, + which_trunk="rear", + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = 255 @@ -66,8 +69,11 @@ async def unlock(self): async def lock(self): """Close the rear trunk.""" if not self.is_locked(): - data = await self._controller.command( - self._id, "actuate_trunk", {"which_trunk": "rear"}, wake_if_asleep=True + data = await self._controller.api( + "ACTUATE_TRUNK", + path_vars={"vehicle_id": self._id}, + which_trunk="rear", + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = 0 @@ -124,8 +130,11 @@ def is_locked(self): async def unlock(self): """Open the front trunk (frunk).""" if self.is_locked(): - data = await self._controller.command( - self._id, "actuate_trunk", {"which_trunk": "front"}, wake_if_asleep=True + data = await self._controller.api( + "ACTUATE_TRUNK", + path_vars={"vehicle_id": self._id}, + which_trunk="front", + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = 255 @@ -134,8 +143,11 @@ async def unlock(self): async def lock(self): """Close the front trunk (frunk).""" if not self.is_locked(): - data = await self._controller.command( - self._id, "actuate_trunk", {"which_trunk": "front"}, wake_if_asleep=True + data = await self._controller.api( + "ACTUATE_TRUNK", + path_vars={"vehicle_id": self._id}, + which_trunk="front", + wake_if_asleep=True, ) if data and data["response"]["result"]: self.__lock_state = 0 diff --git a/tests/tesla_mock.py b/tests/tesla_mock.py index db9a9e5a..cb6490e5 100644 --- a/tests/tesla_mock.py +++ b/tests/tesla_mock.py @@ -23,6 +23,7 @@ def __init__(self, monkeypatch) -> None: self._monkeypatch = monkeypatch self._monkeypatch.setattr(Controller, "connect", self.mock_connect) self._monkeypatch.setattr(Controller, "command", self.mock_command) + self._monkeypatch.setattr(Controller, "api", self.mock_api) self._monkeypatch.setattr( Controller, "get_charging_params", self.mock_get_charging_params ) @@ -63,6 +64,11 @@ def __init__(self, monkeypatch) -> None: self._vehicle["vehicle_state"] = self._vehicle_state self._vehicle["vehicle_config"] = self._vehicle_config + def mock_api(self, *args, **kwargs): + # pylint: disable=unused-argument + """ Mock controller's api method.""" + return self.controller_api() + def mock_connect(self, *args, **kwargs): # pylint: disable=unused-argument """ Mock controller's connect method.""" @@ -123,6 +129,11 @@ def controller_connect(): """ Monkeypatch for controller.connect().""" return ("abc123", "cba321") + @staticmethod + async def controller_api(): + """ Monkeypatch for controller.command().""" + return RESULT_OK + @staticmethod async def controller_command(): """ Monkeypatch for controller.command()."""