diff --git a/homeassistant/components/teslemetry/__init__.py b/homeassistant/components/teslemetry/__init__.py index 16d32736165..387ebd1039e 100644 --- a/homeassistant/components/teslemetry/__init__.py +++ b/homeassistant/components/teslemetry/__init__.py @@ -102,6 +102,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) - manufacturer="Tesla", configuration_url="https://teslemetry.com/console", name=product.get("site_name", "Energy Site"), + serial_number=str(site_id), ) energysites.append( diff --git a/homeassistant/components/teslemetry/button.py b/homeassistant/components/teslemetry/button.py index 433279f21da..011879525b8 100644 --- a/homeassistant/components/teslemetry/button.py +++ b/homeassistant/components/teslemetry/button.py @@ -14,6 +14,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .entity import TeslemetryVehicleEntity +from .helpers import handle_vehicle_command from .models import TeslemetryVehicleData @@ -84,4 +85,4 @@ class TeslemetryButtonEntity(TeslemetryVehicleEntity, ButtonEntity): """Press the button.""" await self.wake_up_if_asleep() if self.entity_description.func: - await self.handle_command(self.entity_description.func(self)) + await handle_vehicle_command(self.entity_description.func(self)) diff --git a/homeassistant/components/teslemetry/climate.py b/homeassistant/components/teslemetry/climate.py index a70dc5a360a..1158822f960 100644 --- a/homeassistant/components/teslemetry/climate.py +++ b/homeassistant/components/teslemetry/climate.py @@ -26,6 +26,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .const import DOMAIN, TeslemetryClimateSide from .entity import TeslemetryVehicleEntity +from .helpers import handle_vehicle_command from .models import TeslemetryVehicleData DEFAULT_MIN_TEMP = 15 @@ -114,7 +115,7 @@ class TeslemetryClimateEntity(TeslemetryVehicleEntity, ClimateEntity): self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.auto_conditioning_start()) + await handle_vehicle_command(self.api.auto_conditioning_start()) self._attr_hvac_mode = HVACMode.HEAT_COOL self.async_write_ha_state() @@ -124,7 +125,7 @@ class TeslemetryClimateEntity(TeslemetryVehicleEntity, ClimateEntity): self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.auto_conditioning_stop()) + await handle_vehicle_command(self.api.auto_conditioning_stop()) self._attr_hvac_mode = HVACMode.OFF self._attr_preset_mode = self._attr_preset_modes[0] @@ -135,7 +136,7 @@ class TeslemetryClimateEntity(TeslemetryVehicleEntity, ClimateEntity): if temp := kwargs.get(ATTR_TEMPERATURE): await self.wake_up_if_asleep() - await self.handle_command( + await handle_vehicle_command( self.api.set_temps( driver_temp=temp, passenger_temp=temp, @@ -159,7 +160,7 @@ class TeslemetryClimateEntity(TeslemetryVehicleEntity, ClimateEntity): async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the climate preset mode.""" await self.wake_up_if_asleep() - await self.handle_command( + await handle_vehicle_command( self.api.set_climate_keeper_mode( climate_keeper_mode=self._attr_preset_modes.index(preset_mode) ) @@ -261,7 +262,7 @@ class TeslemetryCabinOverheatProtectionEntity(TeslemetryVehicleEntity, ClimateEn ) await self.wake_up_if_asleep() - await self.handle_command(self.api.set_cop_temp(cop_mode)) + await handle_vehicle_command(self.api.set_cop_temp(cop_mode)) self._attr_target_temperature = temp if mode := kwargs.get(ATTR_HVAC_MODE): @@ -271,15 +272,15 @@ class TeslemetryCabinOverheatProtectionEntity(TeslemetryVehicleEntity, ClimateEn async def _async_set_cop(self, hvac_mode: HVACMode) -> None: if hvac_mode == HVACMode.OFF: - await self.handle_command( + await handle_vehicle_command( self.api.set_cabin_overheat_protection(on=False, fan_only=False) ) elif hvac_mode == HVACMode.COOL: - await self.handle_command( + await handle_vehicle_command( self.api.set_cabin_overheat_protection(on=True, fan_only=False) ) elif hvac_mode == HVACMode.FAN_ONLY: - await self.handle_command( + await handle_vehicle_command( self.api.set_cabin_overheat_protection(on=True, fan_only=True) ) diff --git a/homeassistant/components/teslemetry/cover.py b/homeassistant/components/teslemetry/cover.py index 6c08dff6c96..4fbbb5fdb2b 100644 --- a/homeassistant/components/teslemetry/cover.py +++ b/homeassistant/components/teslemetry/cover.py @@ -17,6 +17,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .entity import TeslemetryVehicleEntity +from .helpers import handle_vehicle_command from .models import TeslemetryVehicleData OPEN = 1 @@ -88,7 +89,9 @@ class TeslemetryWindowEntity(TeslemetryVehicleEntity, CoverEntity): """Vent windows.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.window_control(command=WindowCommand.VENT)) + await handle_vehicle_command( + self.api.window_control(command=WindowCommand.VENT) + ) self._attr_is_closed = False self.async_write_ha_state() @@ -96,7 +99,9 @@ class TeslemetryWindowEntity(TeslemetryVehicleEntity, CoverEntity): """Close windows.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.window_control(command=WindowCommand.CLOSE)) + await handle_vehicle_command( + self.api.window_control(command=WindowCommand.CLOSE) + ) self._attr_is_closed = True self.async_write_ha_state() @@ -127,7 +132,7 @@ class TeslemetryChargePortEntity(TeslemetryVehicleEntity, CoverEntity): """Open charge port.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.charge_port_door_open()) + await handle_vehicle_command(self.api.charge_port_door_open()) self._attr_is_closed = False self.async_write_ha_state() @@ -135,7 +140,7 @@ class TeslemetryChargePortEntity(TeslemetryVehicleEntity, CoverEntity): """Close charge port.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.charge_port_door_close()) + await handle_vehicle_command(self.api.charge_port_door_close()) self._attr_is_closed = True self.async_write_ha_state() @@ -162,7 +167,7 @@ class TeslemetryFrontTrunkEntity(TeslemetryVehicleEntity, CoverEntity): """Open front trunk.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.actuate_trunk(Trunk.FRONT)) + await handle_vehicle_command(self.api.actuate_trunk(Trunk.FRONT)) self._attr_is_closed = False self.async_write_ha_state() @@ -198,7 +203,7 @@ class TeslemetryRearTrunkEntity(TeslemetryVehicleEntity, CoverEntity): if self.is_closed is not False: self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.actuate_trunk(Trunk.REAR)) + await handle_vehicle_command(self.api.actuate_trunk(Trunk.REAR)) self._attr_is_closed = False self.async_write_ha_state() @@ -207,6 +212,6 @@ class TeslemetryRearTrunkEntity(TeslemetryVehicleEntity, CoverEntity): if self.is_closed is not True: self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.actuate_trunk(Trunk.REAR)) + await handle_vehicle_command(self.api.actuate_trunk(Trunk.REAR)) self._attr_is_closed = True self.async_write_ha_state() diff --git a/homeassistant/components/teslemetry/entity.py b/homeassistant/components/teslemetry/entity.py index dd6e6e575c2..74c1fdd52b1 100644 --- a/homeassistant/components/teslemetry/entity.py +++ b/homeassistant/components/teslemetry/entity.py @@ -1,22 +1,21 @@ """Teslemetry parent entity class.""" from abc import abstractmethod -import asyncio from typing import Any from tesla_fleet_api import EnergySpecific, VehicleSpecific -from tesla_fleet_api.exceptions import TeslaFleetError -from homeassistant.exceptions import HomeAssistantError, ServiceValidationError +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.device_registry import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN, LOGGER, TeslemetryState +from .const import DOMAIN from .coordinator import ( TeslemetryEnergySiteInfoCoordinator, TeslemetryEnergySiteLiveCoordinator, TeslemetryVehicleDataCoordinator, ) +from .helpers import wake_up_vehicle from .models import TeslemetryEnergyData, TeslemetryVehicleData @@ -76,15 +75,6 @@ class TeslemetryEntity( """Return True if a specific value is in coordinator data.""" return self.key in self.coordinator.data - async def handle_command(self, command) -> dict[str, Any]: - """Handle a command.""" - try: - result = await command - except TeslaFleetError as e: - raise HomeAssistantError(f"Teslemetry command failed, {e.message}") from e - LOGGER.debug("Command result: %s", result) - return result - def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" self._async_update_attrs() @@ -113,7 +103,7 @@ class TeslemetryVehicleEntity(TeslemetryEntity): """Initialize common aspects of a Teslemetry entity.""" self._attr_unique_id = f"{data.vin}-{key}" - self._wakelock = data.wakelock + self.vehicle = data self._attr_device_info = data.device super().__init__(data.coordinator, data.api, key) @@ -125,44 +115,7 @@ class TeslemetryVehicleEntity(TeslemetryEntity): async def wake_up_if_asleep(self) -> None: """Wake up the vehicle if its asleep.""" - async with self._wakelock: - times = 0 - while self.coordinator.data["state"] != TeslemetryState.ONLINE: - try: - if times == 0: - cmd = await self.api.wake_up() - else: - cmd = await self.api.vehicle() - state = cmd["response"]["state"] - except TeslaFleetError as e: - raise HomeAssistantError(str(e)) from e - self.coordinator.data["state"] = state - if state != TeslemetryState.ONLINE: - times += 1 - if times >= 4: # Give up after 30 seconds total - raise HomeAssistantError("Could not wake up vehicle") - await asyncio.sleep(times * 5) - - async def handle_command(self, command) -> dict[str, Any]: - """Handle a vehicle command.""" - result = await super().handle_command(command) - if (response := result.get("response")) is None: - if error := result.get("error"): - # No response with error - raise HomeAssistantError(error) - # No response without error (unexpected) - raise HomeAssistantError(f"Unknown response: {response}") - if (result := response.get("result")) is not True: - if reason := response.get("reason"): - if reason in ("already_set", "not_charging", "requested"): - # Reason is acceptable - return result - # Result of false with reason - raise HomeAssistantError(reason) - # Result of false without reason (unexpected) - raise HomeAssistantError("Command failed with no reason") - # Response with result of true - return result + await wake_up_vehicle(self.vehicle) class TeslemetryEnergyLiveEntity(TeslemetryEntity): diff --git a/homeassistant/components/teslemetry/helpers.py b/homeassistant/components/teslemetry/helpers.py new file mode 100644 index 00000000000..a8cfa1051f1 --- /dev/null +++ b/homeassistant/components/teslemetry/helpers.py @@ -0,0 +1,63 @@ +"""Teslemetry helper functions.""" + +import asyncio +from typing import Any + +from tesla_fleet_api.exceptions import TeslaFleetError + +from homeassistant.exceptions import HomeAssistantError + +from .const import LOGGER, TeslemetryState + + +async def wake_up_vehicle(vehicle) -> None: + """Wake up a vehicle.""" + async with vehicle.wakelock: + times = 0 + while vehicle.coordinator.data["state"] != TeslemetryState.ONLINE: + try: + if times == 0: + cmd = await vehicle.api.wake_up() + else: + cmd = await vehicle.api.vehicle() + state = cmd["response"]["state"] + except TeslaFleetError as e: + raise HomeAssistantError(str(e)) from e + vehicle.coordinator.data["state"] = state + if state != TeslemetryState.ONLINE: + times += 1 + if times >= 4: # Give up after 30 seconds total + raise HomeAssistantError("Could not wake up vehicle") + await asyncio.sleep(times * 5) + + +async def handle_command(command) -> dict[str, Any]: + """Handle a command.""" + try: + result = await command + except TeslaFleetError as e: + raise HomeAssistantError(f"Teslemetry command failed, {e.message}") from e + LOGGER.debug("Command result: %s", result) + return result + + +async def handle_vehicle_command(command) -> dict[str, Any]: + """Handle a vehicle command.""" + result = await handle_command(command) + if (response := result.get("response")) is None: + if error := result.get("error"): + # No response with error + raise HomeAssistantError(error) + # No response without error (unexpected) + raise HomeAssistantError(f"Unknown response: {response}") + if (result := response.get("result")) is not True: + if reason := response.get("reason"): + if reason in ("already_set", "not_charging", "requested"): + # Reason is acceptable + return result + # Result of false with reason + raise HomeAssistantError(reason) + # Result of false without reason (unexpected) + raise HomeAssistantError("Command failed with no reason") + # Response with result of true + return result diff --git a/homeassistant/components/teslemetry/lock.py b/homeassistant/components/teslemetry/lock.py index d40d389bfb9..2201b898d66 100644 --- a/homeassistant/components/teslemetry/lock.py +++ b/homeassistant/components/teslemetry/lock.py @@ -14,6 +14,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .const import DOMAIN from .entity import TeslemetryVehicleEntity +from .helpers import handle_vehicle_command from .models import TeslemetryVehicleData ENGAGED = "Engaged" @@ -52,7 +53,7 @@ class TeslemetryVehicleLockEntity(TeslemetryVehicleEntity, LockEntity): """Lock the doors.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.door_lock()) + await handle_vehicle_command(self.api.door_lock()) self._attr_is_locked = True self.async_write_ha_state() @@ -60,7 +61,7 @@ class TeslemetryVehicleLockEntity(TeslemetryVehicleEntity, LockEntity): """Unlock the doors.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.door_unlock()) + await handle_vehicle_command(self.api.door_unlock()) self._attr_is_locked = False self.async_write_ha_state() @@ -95,6 +96,6 @@ class TeslemetryCableLockEntity(TeslemetryVehicleEntity, LockEntity): """Unlock charge cable lock.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.charge_port_door_open()) + await handle_vehicle_command(self.api.charge_port_door_open()) self._attr_is_locked = False self.async_write_ha_state() diff --git a/homeassistant/components/teslemetry/manifest.json b/homeassistant/components/teslemetry/manifest.json index 14ac4a315d4..36a655b3b11 100644 --- a/homeassistant/components/teslemetry/manifest.json +++ b/homeassistant/components/teslemetry/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/teslemetry", "iot_class": "cloud_polling", "loggers": ["tesla-fleet-api"], - "requirements": ["tesla-fleet-api==0.5.12"] + "requirements": ["tesla-fleet-api==0.6.1"] } diff --git a/homeassistant/components/teslemetry/media_player.py b/homeassistant/components/teslemetry/media_player.py index 0f8533109ae..31c58e9505b 100644 --- a/homeassistant/components/teslemetry/media_player.py +++ b/homeassistant/components/teslemetry/media_player.py @@ -15,6 +15,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .entity import TeslemetryVehicleEntity +from .helpers import handle_vehicle_command from .models import TeslemetryVehicleData STATES = { @@ -114,7 +115,7 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity): """Set volume level, range 0..1.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command( + await handle_vehicle_command( self.api.adjust_volume(int(volume * self._volume_max)) ) self._attr_volume_level = volume @@ -125,7 +126,7 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity): if self.state != MediaPlayerState.PLAYING: self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.media_toggle_playback()) + await handle_vehicle_command(self.api.media_toggle_playback()) self._attr_state = MediaPlayerState.PLAYING self.async_write_ha_state() @@ -134,7 +135,7 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity): if self.state == MediaPlayerState.PLAYING: self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.media_toggle_playback()) + await handle_vehicle_command(self.api.media_toggle_playback()) self._attr_state = MediaPlayerState.PAUSED self.async_write_ha_state() @@ -142,10 +143,10 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity): """Send next track command.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.media_next_track()) + await handle_vehicle_command(self.api.media_next_track()) async def async_media_previous_track(self) -> None: """Send previous track command.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.media_prev_track()) + await handle_vehicle_command(self.api.media_prev_track()) diff --git a/homeassistant/components/teslemetry/number.py b/homeassistant/components/teslemetry/number.py index 592c20c3e4a..258fc5c5559 100644 --- a/homeassistant/components/teslemetry/number.py +++ b/homeassistant/components/teslemetry/number.py @@ -23,6 +23,7 @@ from homeassistant.helpers.icon import icon_for_battery_level from . import TeslemetryConfigEntry from .entity import TeslemetryEnergyInfoEntity, TeslemetryVehicleEntity +from .helpers import handle_command, handle_vehicle_command from .models import TeslemetryEnergyData, TeslemetryVehicleData @@ -163,7 +164,7 @@ class TeslemetryVehicleNumberEntity(TeslemetryVehicleEntity, NumberEntity): value = int(value) self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.entity_description.func(self.api, value)) + await handle_vehicle_command(self.entity_description.func(self.api, value)) self._attr_native_value = value self.async_write_ha_state() @@ -198,6 +199,6 @@ class TeslemetryEnergyInfoNumberSensorEntity(TeslemetryEnergyInfoEntity, NumberE """Set new value.""" value = int(value) self.raise_for_scope() - await self.handle_command(self.entity_description.func(self.api, value)) + await handle_command(self.entity_description.func(self.api, value)) self._attr_native_value = value self.async_write_ha_state() diff --git a/homeassistant/components/teslemetry/select.py b/homeassistant/components/teslemetry/select.py index c9c8cb1ec20..10d925ad94d 100644 --- a/homeassistant/components/teslemetry/select.py +++ b/homeassistant/components/teslemetry/select.py @@ -14,6 +14,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .entity import TeslemetryEnergyInfoEntity, TeslemetryVehicleEntity +from .helpers import handle_command, handle_vehicle_command from .models import TeslemetryEnergyData, TeslemetryVehicleData OFF = "off" @@ -146,8 +147,8 @@ class TeslemetrySeatHeaterSelectEntity(TeslemetryVehicleEntity, SelectEntity): level = self._attr_options.index(option) # AC must be on to turn on seat heater if level and not self.get("climate_state_is_climate_on"): - await self.handle_command(self.api.auto_conditioning_start()) - await self.handle_command( + await handle_vehicle_command(self.api.auto_conditioning_start()) + await handle_vehicle_command( self.api.remote_seat_heater_request(self.entity_description.position, level) ) self._attr_current_option = option @@ -191,8 +192,8 @@ class TeslemetryWheelHeaterSelectEntity(TeslemetryVehicleEntity, SelectEntity): level = self._attr_options.index(option) # AC must be on to turn on steering wheel heater if level and not self.get("climate_state_is_climate_on"): - await self.handle_command(self.api.auto_conditioning_start()) - await self.handle_command( + await handle_vehicle_command(self.api.auto_conditioning_start()) + await handle_vehicle_command( self.api.remote_steering_wheel_heat_level_request(level) ) self._attr_current_option = option @@ -224,7 +225,7 @@ class TeslemetryOperationSelectEntity(TeslemetryEnergyInfoEntity, SelectEntity): async def async_select_option(self, option: str) -> None: """Change the selected option.""" self.raise_for_scope() - await self.handle_command(self.api.operation(option)) + await handle_command(self.api.operation(option)) self._attr_current_option = option self.async_write_ha_state() @@ -254,7 +255,7 @@ class TeslemetryExportRuleSelectEntity(TeslemetryEnergyInfoEntity, SelectEntity) async def async_select_option(self, option: str) -> None: """Change the selected option.""" self.raise_for_scope() - await self.handle_command( + await handle_command( self.api.grid_import_export(customer_preferred_export_rule=option) ) self._attr_current_option = option diff --git a/homeassistant/components/teslemetry/switch.py b/homeassistant/components/teslemetry/switch.py index d7d5095db90..e23d34f242a 100644 --- a/homeassistant/components/teslemetry/switch.py +++ b/homeassistant/components/teslemetry/switch.py @@ -19,6 +19,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .entity import TeslemetryEnergyInfoEntity, TeslemetryVehicleEntity +from .helpers import handle_command, handle_vehicle_command from .models import TeslemetryEnergyData, TeslemetryVehicleData @@ -156,7 +157,7 @@ class TeslemetryVehicleSwitchEntity(TeslemetryVehicleEntity, TeslemetrySwitchEnt """Turn on the Switch.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.entity_description.on_func(self.api)) + await handle_vehicle_command(self.entity_description.on_func(self.api)) self._attr_is_on = True self.async_write_ha_state() @@ -164,7 +165,7 @@ class TeslemetryVehicleSwitchEntity(TeslemetryVehicleEntity, TeslemetrySwitchEnt """Turn off the Switch.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.entity_description.off_func(self.api)) + await handle_vehicle_command(self.entity_description.off_func(self.api)) self._attr_is_on = False self.async_write_ha_state() @@ -205,7 +206,7 @@ class TeslemetryChargeFromGridSwitchEntity( async def async_turn_on(self, **kwargs: Any) -> None: """Turn on the Switch.""" self.raise_for_scope() - await self.handle_command( + await handle_command( self.api.grid_import_export( disallow_charge_from_grid_with_solar_installed=False ) @@ -216,7 +217,7 @@ class TeslemetryChargeFromGridSwitchEntity( async def async_turn_off(self, **kwargs: Any) -> None: """Turn off the Switch.""" self.raise_for_scope() - await self.handle_command( + await handle_command( self.api.grid_import_export( disallow_charge_from_grid_with_solar_installed=True ) @@ -247,13 +248,13 @@ class TeslemetryStormModeSwitchEntity( async def async_turn_on(self, **kwargs: Any) -> None: """Turn on the Switch.""" self.raise_for_scope() - await self.handle_command(self.api.storm_mode(enabled=True)) + await handle_command(self.api.storm_mode(enabled=True)) self._attr_is_on = True self.async_write_ha_state() async def async_turn_off(self, **kwargs: Any) -> None: """Turn off the Switch.""" self.raise_for_scope() - await self.handle_command(self.api.storm_mode(enabled=False)) + await handle_command(self.api.storm_mode(enabled=False)) self._attr_is_on = False self.async_write_ha_state() diff --git a/homeassistant/components/teslemetry/update.py b/homeassistant/components/teslemetry/update.py index 89393700c1f..74ecec8020d 100644 --- a/homeassistant/components/teslemetry/update.py +++ b/homeassistant/components/teslemetry/update.py @@ -12,6 +12,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import TeslemetryConfigEntry from .entity import TeslemetryVehicleEntity +from .helpers import handle_vehicle_command from .models import TeslemetryVehicleData AVAILABLE = "available" @@ -102,6 +103,6 @@ class TeslemetryUpdateEntity(TeslemetryVehicleEntity, UpdateEntity): """Install an update.""" self.raise_for_scope() await self.wake_up_if_asleep() - await self.handle_command(self.api.schedule_software_update(offset_sec=60)) + await handle_vehicle_command(self.api.schedule_software_update(offset_sec=60)) self._attr_in_progress = True self.async_write_ha_state() diff --git a/requirements_all.txt b/requirements_all.txt index 14ede992a85..367fe4de0f4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2707,7 +2707,7 @@ temperusb==1.6.1 # tensorflow==2.5.0 # homeassistant.components.teslemetry -tesla-fleet-api==0.5.12 +tesla-fleet-api==0.6.1 # homeassistant.components.powerwall tesla-powerwall==0.5.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index aad6dc6124a..21b41dc1c28 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2105,7 +2105,7 @@ temescal==0.5 temperusb==1.6.1 # homeassistant.components.teslemetry -tesla-fleet-api==0.5.12 +tesla-fleet-api==0.6.1 # homeassistant.components.powerwall tesla-powerwall==0.5.2 diff --git a/tests/components/teslemetry/snapshots/test_init.ambr b/tests/components/teslemetry/snapshots/test_init.ambr index 434e9025ac7..951e4557bdd 100644 --- a/tests/components/teslemetry/snapshots/test_init.ambr +++ b/tests/components/teslemetry/snapshots/test_init.ambr @@ -23,7 +23,7 @@ 'model': 'Powerwall 2, Tesla Backup Gateway 2', 'name': 'Energy Site', 'name_by_user': None, - 'serial_number': None, + 'serial_number': '123456', 'suggested_area': None, 'sw_version': None, 'via_device_id': None, diff --git a/tests/components/teslemetry/test_climate.py b/tests/components/teslemetry/test_climate.py index a737fc9f376..250413396c1 100644 --- a/tests/components/teslemetry/test_climate.py +++ b/tests/components/teslemetry/test_climate.py @@ -343,7 +343,7 @@ async def test_asleep_or_offline( mock_wake_up.return_value = WAKE_UP_ASLEEP mock_vehicle.return_value = WAKE_UP_ASLEEP with ( - patch("homeassistant.components.teslemetry.entity.asyncio.sleep"), + patch("homeassistant.components.teslemetry.helpers.asyncio.sleep"), pytest.raises(HomeAssistantError) as error, ): await hass.services.async_call(