diff --git a/teslajsonpy/car.py b/teslajsonpy/car.py index eec69b8b..cb283d1b 100644 --- a/teslajsonpy/car.py +++ b/teslajsonpy/car.py @@ -650,9 +650,26 @@ def scheduled_charging_start_time_app(self) -> int: ) async def _send_command( - self, name: str, *, path_vars: dict, wake_if_asleep: bool = False, **kwargs + self, + name: str, + *, + additional_path_vars: dict = None, + wake_if_asleep: bool = True, + **kwargs, ) -> dict: - """Wrap commands sent to Tesla API.""" + """Wrap commands sent to Tesla API. + + Args + name: Name of command to send, from endpoints.json + additional_path_vars: Additional URI variables ('vehicle_id' already included) + wake_if_asleep: (default True) Wake car if it's asleep before sending the command + **kwargs: Any additional parameters for the api call + + """ + path_vars = {"vehicle_id": self.id} + if additional_path_vars: + path_vars.update(additional_path_vars) + _LOGGER.debug("Sending command: %s", name) data = await self._controller.api( name, path_vars=path_vars, wake_if_asleep=wake_if_asleep, **kwargs @@ -690,11 +707,10 @@ def update_car_info(self, car: dict) -> None: async def change_charge_limit(self, value: float) -> None: """Send command to change charge limit.""" + # Only wake car if the value is different + wake_if_asleep = value != self.charge_limit_soc data = await self._send_command( - "CHANGE_CHARGE_LIMIT", - path_vars={"vehicle_id": self.id}, - percent=int(value), - wake_if_asleep=True, + "CHANGE_CHARGE_LIMIT", percent=int(value), wake_if_asleep=wake_if_asleep ) if data and data["response"]["result"] is True: @@ -703,11 +719,7 @@ async def change_charge_limit(self, value: float) -> None: async def charge_port_door_close(self) -> None: """Send command to close charge port door.""" - data = await self._send_command( - "CHARGE_PORT_DOOR_CLOSE", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + data = await self._send_command("CHARGE_PORT_DOOR_CLOSE") if data and data["response"]["result"] is True: params = {"charge_port_door_open": False} @@ -715,11 +727,7 @@ async def charge_port_door_close(self) -> None: async def charge_port_door_open(self) -> None: """Send command to open charge port door.""" - data = await self._send_command( - "CHARGE_PORT_DOOR_OPEN", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + data = await self._send_command("CHARGE_PORT_DOOR_OPEN") if data and data["response"]["result"] is True: params = {"charge_port_door_open": True} @@ -727,29 +735,15 @@ async def charge_port_door_open(self) -> None: async def flash_lights(self) -> None: """Send command to flash lights.""" - await self._send_command( - "FLASH_LIGHTS", - path_vars={"vehicle_id": self.id}, - on=True, - wake_if_asleep=True, - ) + await self._send_command("FLASH_LIGHTS", on=True) async def honk_horn(self) -> None: """Send command to honk horn.""" - await self._send_command( - "HONK_HORN", - path_vars={"vehicle_id": self.id}, - on=True, - wake_if_asleep=True, - ) + await self._send_command("HONK_HORN", on=True) async def lock(self) -> None: """Send lock command.""" - data = await self._send_command( - "LOCK", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + data = await self._send_command("LOCK") if data and data["response"]["result"] is True: params = {"locked": True} self._vehicle_data["vehicle_state"].update(params) @@ -763,13 +757,13 @@ async def remote_seat_heater_request(self, level: int, seat_id: int) -> None: 5 (rear right), 6 (third row left), 7 (third row right) """ - + # If car is asleep the heater is already off + wake_if_asleep = level > 0 data = await self._send_command( "REMOTE_SEAT_HEATER_REQUEST", - path_vars={"vehicle_id": self.id}, heater=seat_id, level=level, - wake_if_asleep=True, + wake_if_asleep=wake_if_asleep, ) if data and data["response"]["result"] is True: params = {f"seat_heater_{SEAT_ID_MAP[seat_id]}": level} @@ -784,28 +778,21 @@ def get_seat_heater_status(self, seat_id: int) -> int: async def schedule_software_update(self, offset_sec: Optional[int] = 0) -> None: """Send command to install software update.""" - await self._send_command( - "SCHEDULE_SOFTWARE_UPDATE", - path_vars={"vehicle_id": self.id}, - offset_sec=offset_sec, - wake_if_asleep=True, - ) + await self._send_command("SCHEDULE_SOFTWARE_UPDATE", offset_sec=offset_sec) async def set_charging_amps(self, value: float) -> None: """Send command to set charging amps.""" + # Only wake car if the value is different + wake_if_asleep = value != self._vehicle_data.get("charge_state", {}).get( + "charge_amps" + ) data = await self._send_command( - "CHARGING_AMPS", - path_vars={"vehicle_id": self.id}, - charging_amps=int(value), - wake_if_asleep=True, + "CHARGING_AMPS", charging_amps=int(value), wake_if_asleep=wake_if_asleep ) # A second API call allows setting below 5 Amps if value < 5: data = await self._send_command( - "CHARGING_AMPS", - path_vars={"vehicle_id": self.id}, - charging_amps=int(value), - wake_if_asleep=True, + "CHARGING_AMPS", charging_amps=int(value), wake_if_asleep=wake_if_asleep ) if data and data["response"]["result"] is True: @@ -831,11 +818,7 @@ async def set_cabin_overheat_protection(self, option: str) -> None: fan_only = False data = await self._send_command( - "SET_CABIN_OVERHEAT_PROTECTION", - path_vars={"vehicle_id": self.id}, - on=body_on, - fan_only=fan_only, - wake_if_asleep=True, + "SET_CABIN_OVERHEAT_PROTECTION", on=body_on, fan_only=fan_only ) if data and data["response"]["result"] is True: params = {"cabin_overheat_protection": option} @@ -848,11 +831,12 @@ async def set_climate_keeper_mode(self, keeper_id: int) -> None: keeper_id: 1 (keep on), 2 (dog mode), 3 (camp mode) """ + # If car is asleep, climate is already off + wake_if_asleep = keeper_id > 0 data = await self._send_command( "SET_CLIMATE_KEEPER_MODE", - path_vars={"vehicle_id": self.id}, climate_keeper_mode=keeper_id, - wake_if_asleep=True, + wake_if_asleep=wake_if_asleep, ) if data and data["response"]["result"] is True: params = { @@ -868,16 +852,14 @@ async def remote_auto_seat_climate_request( Args seat_id: 0 (front left), 1 (front right) - enable: 'True' to enable, 'False' to diable + enable: 'True' to enable, 'False' to disable """ data = await self._send_command( "REMOTE_AUTO_SEAT_CLIMATE_REQUEST", - path_vars={"vehicle_id": self.id}, auto_seat_position=seat_id, auto_climate_on=enable, - wake_if_asleep=True, ) if data and data["response"]["result"] is True: params = {f"auto_seat_climate_{SEAT_ID_MAP[seat_id]}": enable} @@ -886,10 +868,7 @@ async def remote_auto_seat_climate_request( async def set_heated_steering_wheel(self, value: bool) -> None: """Send command to set heated steering wheel.""" data = await self._send_command( - "REMOTE_STEERING_WHEEL_HEATER_REQUEST", - path_vars={"vehicle_id": self.id}, - on=value, - wake_if_asleep=True, + "REMOTE_STEERING_WHEEL_HEATER_REQUEST", on=value ) if data and data["response"]["result"] is True: @@ -904,11 +883,8 @@ async def set_hvac_mode(self, value: str) -> None: """ if value == "off": - data = await self._send_command( - "CLIMATE_OFF", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + # If car is asleep, climate is already off + data = await self._send_command("CLIMATE_OFF", wake_if_asleep=False) if data and data["response"]["result"] is True: # Set additional values if turning HVAC off after defrost max params = { @@ -922,11 +898,7 @@ async def set_hvac_mode(self, value: str) -> None: self._vehicle_data["climate_state"].update(params) elif value == "on": - data = await self._send_command( - "CLIMATE_ON", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + data = await self._send_command("CLIMATE_ON") if data and data["response"]["result"] is True: params = {"is_climate_on": True} self._vehicle_data["climate_state"].update(params) @@ -938,11 +910,10 @@ async def set_max_defrost(self, state: int) -> None: state: 2 = on, 0 = off """ + # If car is asleep, climate is already off + wake_if_asleep = state > 0 data = await self._send_command( - "MAX_DEFROST", - path_vars={"vehicle_id": self.id}, - on=state, - wake_if_asleep=True, + "MAX_DEFROST", on=state, wake_if_asleep=wake_if_asleep ) if data and data["response"]["result"] is True: self._previous_driver_temp = self.driver_temp_setting @@ -973,11 +944,9 @@ async def set_max_defrost(self, state: int) -> None: async def set_sentry_mode(self, value: bool) -> None: """Send command to set sentry mode.""" + # If car is asleep, sentry is already off data = await self._send_command( - "SET_SENTRY_MODE", - path_vars={"vehicle_id": self.id}, - on=value, - wake_if_asleep=True, + "SET_SENTRY_MODE", on=value, wake_if_asleep=value ) if data and data["response"]["result"] is True: @@ -987,11 +956,7 @@ async def set_sentry_mode(self, value: bool) -> None: async def set_temperature(self, temp: float) -> None: """Send command to set temperature.""" data = await self._send_command( - "CHANGE_CLIMATE_TEMPERATURE_SETTING", - path_vars={"vehicle_id": self.id}, - driver_temp=temp, - passenger_temp=temp, - wake_if_asleep=True, + "CHANGE_CLIMATE_TEMPERATURE_SETTING", driver_temp=temp, passenger_temp=temp ) if data and data["response"]["result"] is True: params = {"driver_temp_setting": temp} @@ -999,23 +964,16 @@ async def set_temperature(self, temp: float) -> None: async def start_charge(self) -> None: """Send command to start charge.""" - data = await self._send_command( - "START_CHARGE", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + data = await self._send_command("START_CHARGE") if data and data["response"]["result"] is True: params = {"charging_state": "Charging"} self._vehicle_data["charge_state"].update(params) async def stop_charge(self) -> None: - """Send command to start charge.""" - data = await self._send_command( - "STOP_CHARGE", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + """Send command to stop charge.""" + # If car is asleep, it's not charging + data = await self._send_command("STOP_CHARGE", wake_if_asleep=False) if data and data["response"]["result"] is True: params = {"charging_state": "Stopped"} @@ -1023,21 +981,13 @@ async def stop_charge(self) -> None: async def wake_up(self) -> None: """Send command to wake up.""" - await self._send_command( - "WAKE_UP", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + # Avoid wake wrapper loop for wake command + await self._send_command("WAKE_UP", wake_if_asleep=False) async def toggle_trunk(self) -> None: """Actuate rear trunk.""" prev_is_trunk_closed = self.is_trunk_closed - data = await self._send_command( - "ACTUATE_TRUNK", - path_vars={"vehicle_id": self.id}, - which_trunk="rear", - wake_if_asleep=True, - ) + data = await self._send_command("ACTUATE_TRUNK", which_trunk="rear") if data and data["response"]["result"] is True: if not prev_is_trunk_closed: params = {"rt": 0} @@ -1049,12 +999,7 @@ async def toggle_trunk(self) -> None: async def toggle_frunk(self) -> None: """Actuate front trunk.""" prev_is_frunk_closed = self.is_frunk_closed - data = await self._send_command( - "ACTUATE_TRUNK", - path_vars={"vehicle_id": self.id}, - which_trunk="front", - wake_if_asleep=True, - ) + data = await self._send_command("ACTUATE_TRUNK", which_trunk="front") if data and data["response"]["result"] is True: if not prev_is_frunk_closed: params = {"ft": 0} @@ -1073,13 +1018,7 @@ async def trigger_homelink(self) -> None: lat, long = self._get_lat_long() - data = await self._send_command( - "TRIGGER_HOMELINK", - path_vars={"vehicle_id": self.id}, - lat=lat, - lon=long, - wake_if_asleep=True, - ) + data = await self._send_command("TRIGGER_HOMELINK", lat=lat, lon=long) if data and data["response"]: _LOGGER.debug("Homelink response: %s", data["response"]) @@ -1090,25 +1029,14 @@ async def trigger_homelink(self) -> None: async def unlock(self) -> None: """Send unlock command.""" - data = await self._send_command( - "UNLOCK", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + data = await self._send_command("UNLOCK") if data and data["response"]["result"] is True: params = {"locked": False} self._vehicle_data["vehicle_state"].update(params) async def vent_windows(self) -> None: """Vent Windows.""" - data = await self._send_command( - "WINDOW_CONTROL", - path_vars={"vehicle_id": self.id}, - command="vent", - lat=0, - long=0, - wake_if_asleep=True, - ) + data = await self._send_command("WINDOW_CONTROL", command="vent", lat=0, long=0) if data and data["response"]["result"] is True: params = { "fd_window": 1, @@ -1121,12 +1049,7 @@ async def vent_windows(self) -> None: async def close_windows(self) -> None: """Close Windows.""" data = await self._send_command( - "WINDOW_CONTROL", - path_vars={"vehicle_id": self.id}, - command="close", - lat=self.latitude, - long=self.longitude, - wake_if_asleep=True, + "WINDOW_CONTROL", command="close", lat=self.latitude, long=self.longitude ) if data and data["response"]["result"] is True: params = { @@ -1142,24 +1065,16 @@ async def valet_mode(self, enable, pin=None) -> None: Args enable: True to activate, False to deactivate. - pin: optional, pin not required to activate or deactivate valet mode. Even with a previous PIN set. If you clear the PIN and activate Valet Mode without the parameter, you will only be able to deactivate it from your car's screen by signing into your Tesla account. + pin: optional, pin not required to activate or deactivate valet mode. + Even with a previous PIN set. If you clear the PIN and activate Valet Mode + without the parameter, you will only be able to deactivate it from your + car's screen by signing into your Tesla account. """ if pin: - data = await self._send_command( - "SET_VALET_MODE", - path_vars={"vehicle_id": self.id}, - on=enable, - password=pin, - wake_if_asleep=True, - ) + data = await self._send_command("SET_VALET_MODE", on=enable, password=pin) else: - data = await self._send_command( - "SET_VALET_MODE", - path_vars={"vehicle_id": self.id}, - on=enable, - wake_if_asleep=True, - ) + data = await self._send_command("SET_VALET_MODE", on=enable) if data and data["response"]: _LOGGER.debug("Valet mode response: %s", data["response"]) @@ -1176,11 +1091,7 @@ async def valet_mode(self, enable, pin=None) -> None: async def remote_start(self) -> None: """Remote start.""" - data = await self._send_command( - "REMOTE_START", - path_vars={"vehicle_id": self.id}, - wake_if_asleep=True, - ) + data = await self._send_command("REMOTE_START") if data and data["response"]: _LOGGER.debug("Remote start response: %s", data["response"]) @@ -1201,21 +1112,20 @@ async def set_scheduled_departure( off_peak_charging_weekdays_only: bool, end_off_peak_time: int, ) -> None: - """Send command to set depature time. + """Send command to set departure time. Args enable: Turn on (True) or turn off (False) the scheduled departure. departure_time: Time in minutes after midnight (local time) for the departure. - preconditioning_enabled: Enable (True) or disbale (False) the climate preconditioning. + preconditioning_enabled: Enable (True) or disable (False) the climate preconditioning. preconditioning_weekdays_only: Precondition climate for departure time on weekdays only (True) or all days (False). - off_peak_charging_enabled: Complete charging durring off peak hours (True) or complete charging just before departure time (False). + off_peak_charging_enabled: Complete charging during off peak hours (True) or complete charging just before departure time (False). off_peak_charging_weekdays_only: Complete off peak charging only on weekdays only (True) or all days (False). end_off_peak_time: Time in minutes after midnight when the off peak rate ends. """ data = await self._send_command( "SCHEDULED_DEPARTURE", - path_vars={"vehicle_id": self.id}, enable=enable, departure_time=departure_time, preconditioning_enabled=preconditioning_enabled, @@ -1223,7 +1133,6 @@ async def set_scheduled_departure( off_peak_charging_enabled=off_peak_charging_enabled, off_peak_charging_weekdays_only=off_peak_charging_weekdays_only, end_off_peak_time=end_off_peak_time, - wake_if_asleep=True, ) if data and data["response"]["result"] is True: @@ -1255,13 +1164,7 @@ async def set_scheduled_charging(self, enable: bool, time: int) -> None: time: Time in minutes after midnight (local time) to start charging. """ - data = await self._send_command( - "SCHEDULED_CHARGING", - path_vars={"vehicle_id": self.id}, - enable=enable, - time=time, - wake_if_asleep=True, - ) + data = await self._send_command("SCHEDULED_CHARGING", enable=enable, time=time) if data and data["response"]["result"] is True: if enable: