Code quality improvements for Teslemetry (#123444)
parent
66ab90b518
commit
cad87f51a3
|
@ -107,6 +107,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TeslemetryConfigEntry) -
|
|||
device=device,
|
||||
)
|
||||
)
|
||||
|
||||
elif "energy_site_id" in product and Scope.ENERGY_DEVICE_DATA in scopes:
|
||||
site_id = product["energy_site_id"]
|
||||
if not (
|
||||
|
|
|
@ -120,7 +120,8 @@ class TeslemetryClimateEntity(TeslemetryVehicleEntity, ClimateEntity):
|
|||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Set the climate state to on."""
|
||||
self.raise_for_scope()
|
||||
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.auto_conditioning_start())
|
||||
|
||||
|
@ -129,7 +130,8 @@ class TeslemetryClimateEntity(TeslemetryVehicleEntity, ClimateEntity):
|
|||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Set the climate state to off."""
|
||||
self.raise_for_scope()
|
||||
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.auto_conditioning_stop())
|
||||
|
||||
|
@ -261,10 +263,11 @@ class TeslemetryCabinOverheatProtectionEntity(TeslemetryVehicleEntity, ClimateEn
|
|||
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set the climate temperature."""
|
||||
if not (temp := kwargs.get(ATTR_TEMPERATURE)):
|
||||
return
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
|
||||
if (cop_mode := TEMP_LEVELS.get(temp)) is None:
|
||||
if (temp := kwargs.get(ATTR_TEMPERATURE)) is None or (
|
||||
cop_mode := TEMP_LEVELS.get(temp)
|
||||
) is None:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="invalid_cop_temp",
|
||||
|
@ -297,7 +300,7 @@ class TeslemetryCabinOverheatProtectionEntity(TeslemetryVehicleEntity, ClimateEn
|
|||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the climate mode and state."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await self._async_set_cop(hvac_mode)
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -52,7 +52,6 @@ class TeslemetryVehicleDataCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|||
"""Class to manage fetching data from the Teslemetry API."""
|
||||
|
||||
updated_once: bool
|
||||
pre2021: bool
|
||||
last_active: datetime
|
||||
|
||||
def __init__(
|
||||
|
|
|
@ -79,7 +79,7 @@ class TeslemetryWindowEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||
"""Vent windows."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(
|
||||
self.api.window_control(command=WindowCommand.VENT)
|
||||
|
@ -89,7 +89,7 @@ class TeslemetryWindowEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||
"""Close windows."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(
|
||||
self.api.window_control(command=WindowCommand.CLOSE)
|
||||
|
@ -122,7 +122,7 @@ class TeslemetryChargePortEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||
"""Open charge port."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CHARGING_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.charge_port_door_open())
|
||||
self._attr_is_closed = False
|
||||
|
@ -130,7 +130,7 @@ class TeslemetryChargePortEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||
"""Close charge port."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CHARGING_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.charge_port_door_close())
|
||||
self._attr_is_closed = True
|
||||
|
@ -157,7 +157,7 @@ class TeslemetryFrontTrunkEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||
"""Open front trunk."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.actuate_trunk(Trunk.FRONT))
|
||||
self._attr_is_closed = False
|
||||
|
@ -193,7 +193,7 @@ class TeslemetryRearTrunkEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||
"""Open rear trunk."""
|
||||
if self.is_closed is not False:
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.actuate_trunk(Trunk.REAR))
|
||||
self._attr_is_closed = False
|
||||
|
@ -202,7 +202,7 @@ class TeslemetryRearTrunkEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||
"""Close rear trunk."""
|
||||
if self.is_closed is not True:
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.actuate_trunk(Trunk.REAR))
|
||||
self._attr_is_closed = True
|
||||
|
@ -240,7 +240,7 @@ class TeslemetrySunroofEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||
"""Open sunroof."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.sun_roof_control(SunRoofCommand.VENT))
|
||||
self._attr_is_closed = False
|
||||
|
@ -248,7 +248,7 @@ class TeslemetrySunroofEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||
"""Close sunroof."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.sun_roof_control(SunRoofCommand.CLOSE))
|
||||
self._attr_is_closed = True
|
||||
|
@ -256,7 +256,7 @@ class TeslemetrySunroofEntity(TeslemetryVehicleEntity, CoverEntity):
|
|||
|
||||
async def async_stop_cover(self, **kwargs: Any) -> None:
|
||||
"""Close sunroof."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.sun_roof_control(SunRoofCommand.STOP))
|
||||
self._attr_is_closed = False
|
||||
|
|
|
@ -4,6 +4,7 @@ from abc import abstractmethod
|
|||
from typing import Any
|
||||
|
||||
from tesla_fleet_api import EnergySpecific, VehicleSpecific
|
||||
from tesla_fleet_api.const import Scope
|
||||
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
|
@ -31,6 +32,7 @@ class TeslemetryEntity(
|
|||
"""Parent class for all Teslemetry entities."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
scoped: bool
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -38,12 +40,10 @@ class TeslemetryEntity(
|
|||
| TeslemetryEnergyHistoryCoordinator
|
||||
| TeslemetryEnergySiteLiveCoordinator
|
||||
| TeslemetryEnergySiteInfoCoordinator,
|
||||
api: VehicleSpecific | EnergySpecific,
|
||||
key: str,
|
||||
) -> None:
|
||||
"""Initialize common aspects of a Teslemetry entity."""
|
||||
super().__init__(coordinator)
|
||||
self.api = api
|
||||
self.key = key
|
||||
self._attr_translation_key = self.key
|
||||
self._async_update_attrs()
|
||||
|
@ -87,16 +87,22 @@ class TeslemetryEntity(
|
|||
def _async_update_attrs(self) -> None:
|
||||
"""Update the attributes of the entity."""
|
||||
|
||||
def raise_for_scope(self):
|
||||
def raise_for_scope(self, scope: Scope):
|
||||
"""Raise an error if a scope is not available."""
|
||||
if not self.scoped:
|
||||
raise ServiceValidationError("Missing required scope")
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="missing_scope",
|
||||
translation_placeholders={"scope": scope},
|
||||
)
|
||||
|
||||
|
||||
class TeslemetryVehicleEntity(TeslemetryEntity):
|
||||
"""Parent class for Teslemetry Vehicle entities."""
|
||||
|
||||
_last_update: int = 0
|
||||
api: VehicleSpecific
|
||||
vehicle: TeslemetryVehicleData
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -105,11 +111,11 @@ class TeslemetryVehicleEntity(TeslemetryEntity):
|
|||
) -> None:
|
||||
"""Initialize common aspects of a Teslemetry entity."""
|
||||
|
||||
self._attr_unique_id = f"{data.vin}-{key}"
|
||||
self.api = data.api
|
||||
self.vehicle = data
|
||||
|
||||
self._attr_unique_id = f"{data.vin}-{key}"
|
||||
self._attr_device_info = data.device
|
||||
super().__init__(data.coordinator, data.api, key)
|
||||
super().__init__(data.coordinator, key)
|
||||
|
||||
@property
|
||||
def _value(self) -> Any | None:
|
||||
|
@ -124,31 +130,39 @@ class TeslemetryVehicleEntity(TeslemetryEntity):
|
|||
class TeslemetryEnergyLiveEntity(TeslemetryEntity):
|
||||
"""Parent class for Teslemetry Energy Site Live entities."""
|
||||
|
||||
api: EnergySpecific
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: TeslemetryEnergyData,
|
||||
key: str,
|
||||
) -> None:
|
||||
"""Initialize common aspects of a Teslemetry Energy Site Live entity."""
|
||||
|
||||
self.api = data.api
|
||||
self._attr_unique_id = f"{data.id}-{key}"
|
||||
self._attr_device_info = data.device
|
||||
|
||||
super().__init__(data.live_coordinator, data.api, key)
|
||||
super().__init__(data.live_coordinator, key)
|
||||
|
||||
|
||||
class TeslemetryEnergyInfoEntity(TeslemetryEntity):
|
||||
"""Parent class for Teslemetry Energy Site Info Entities."""
|
||||
|
||||
api: EnergySpecific
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: TeslemetryEnergyData,
|
||||
key: str,
|
||||
) -> None:
|
||||
"""Initialize common aspects of a Teslemetry Energy Site Info entity."""
|
||||
|
||||
self.api = data.api
|
||||
self._attr_unique_id = f"{data.id}-{key}"
|
||||
self._attr_device_info = data.device
|
||||
|
||||
super().__init__(data.info_coordinator, data.api, key)
|
||||
super().__init__(data.info_coordinator, key)
|
||||
|
||||
|
||||
class TeslemetryEnergyHistoryEntity(TeslemetryEntity):
|
||||
|
@ -160,18 +174,19 @@ class TeslemetryEnergyHistoryEntity(TeslemetryEntity):
|
|||
key: str,
|
||||
) -> None:
|
||||
"""Initialize common aspects of a Teslemetry Energy Site Info entity."""
|
||||
|
||||
self.api = data.api
|
||||
self._attr_unique_id = f"{data.id}-{key}"
|
||||
self._attr_device_info = data.device
|
||||
|
||||
super().__init__(data.history_coordinator, data.api, key)
|
||||
super().__init__(data.history_coordinator, key)
|
||||
|
||||
|
||||
class TeslemetryWallConnectorEntity(
|
||||
TeslemetryEntity, CoordinatorEntity[TeslemetryEnergySiteLiveCoordinator]
|
||||
):
|
||||
class TeslemetryWallConnectorEntity(TeslemetryEntity):
|
||||
"""Parent class for Teslemetry Wall Connector Entities."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
api: EnergySpecific
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -180,6 +195,8 @@ class TeslemetryWallConnectorEntity(
|
|||
key: str,
|
||||
) -> None:
|
||||
"""Initialize common aspects of a Teslemetry entity."""
|
||||
|
||||
self.api = data.api
|
||||
self.din = din
|
||||
self._attr_unique_id = f"{data.id}-{din}-{key}"
|
||||
|
||||
|
@ -200,7 +217,7 @@ class TeslemetryWallConnectorEntity(
|
|||
model=model,
|
||||
)
|
||||
|
||||
super().__init__(data.live_coordinator, data.api, key)
|
||||
super().__init__(data.live_coordinator, key)
|
||||
|
||||
@property
|
||||
def _value(self) -> int:
|
||||
|
|
|
@ -7,7 +7,7 @@ from tesla_fleet_api.exceptions import TeslaFleetError
|
|||
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from .const import LOGGER, TeslemetryState
|
||||
from .const import DOMAIN, LOGGER, TeslemetryState
|
||||
|
||||
|
||||
async def wake_up_vehicle(vehicle) -> None:
|
||||
|
@ -22,12 +22,19 @@ async def wake_up_vehicle(vehicle) -> None:
|
|||
cmd = await vehicle.api.vehicle()
|
||||
state = cmd["response"]["state"]
|
||||
except TeslaFleetError as e:
|
||||
raise HomeAssistantError(str(e)) from e
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="wake_up_failed",
|
||||
translation_placeholders={"message": e.message},
|
||||
) 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")
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="wake_up_timeout",
|
||||
)
|
||||
await asyncio.sleep(times * 5)
|
||||
|
||||
|
||||
|
@ -36,18 +43,26 @@ async def handle_command(command) -> dict[str, Any]:
|
|||
try:
|
||||
result = await command
|
||||
except TeslaFleetError as e:
|
||||
raise HomeAssistantError(f"Teslemetry command failed, {e.message}") from e
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="command_exception",
|
||||
translation_placeholders={"message": e.message},
|
||||
) from e
|
||||
LOGGER.debug("Command result: %s", result)
|
||||
return result
|
||||
|
||||
|
||||
async def handle_vehicle_command(command) -> dict[str, Any]:
|
||||
async def handle_vehicle_command(command) -> 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)
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="command_error",
|
||||
translation_placeholders={"error": error},
|
||||
)
|
||||
# No response without error (unexpected)
|
||||
raise HomeAssistantError(f"Unknown response: {response}")
|
||||
if (result := response.get("result")) is not True:
|
||||
|
@ -56,8 +71,14 @@ async def handle_vehicle_command(command) -> dict[str, Any]:
|
|||
# Reason is acceptable
|
||||
return result
|
||||
# Result of false with reason
|
||||
raise HomeAssistantError(reason)
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="command_reason",
|
||||
translation_placeholders={"reason": reason},
|
||||
)
|
||||
# Result of false without reason (unexpected)
|
||||
raise HomeAssistantError("Command failed with no reason")
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN, translation_key="command_no_result"
|
||||
)
|
||||
# Response with result of true
|
||||
return result
|
||||
|
|
|
@ -53,7 +53,7 @@ class TeslemetryVehicleLockEntity(TeslemetryVehicleEntity, LockEntity):
|
|||
|
||||
async def async_lock(self, **kwargs: Any) -> None:
|
||||
"""Lock the doors."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.door_lock())
|
||||
self._attr_is_locked = True
|
||||
|
@ -61,7 +61,7 @@ class TeslemetryVehicleLockEntity(TeslemetryVehicleEntity, LockEntity):
|
|||
|
||||
async def async_unlock(self, **kwargs: Any) -> None:
|
||||
"""Unlock the doors."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.door_unlock())
|
||||
self._attr_is_locked = False
|
||||
|
@ -96,7 +96,7 @@ class TeslemetryCableLockEntity(TeslemetryVehicleEntity, LockEntity):
|
|||
|
||||
async def async_unlock(self, **kwargs: Any) -> None:
|
||||
"""Unlock charge cable lock."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.charge_port_door_open())
|
||||
self._attr_is_locked = False
|
||||
|
|
|
@ -115,7 +115,7 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity):
|
|||
|
||||
async def async_set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level, range 0..1."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(
|
||||
self.api.adjust_volume(int(volume * self._volume_max))
|
||||
|
@ -126,7 +126,7 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity):
|
|||
async def async_media_play(self) -> None:
|
||||
"""Send play command."""
|
||||
if self.state != MediaPlayerState.PLAYING:
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.media_toggle_playback())
|
||||
self._attr_state = MediaPlayerState.PLAYING
|
||||
|
@ -135,7 +135,7 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity):
|
|||
async def async_media_pause(self) -> None:
|
||||
"""Send pause command."""
|
||||
if self.state == MediaPlayerState.PLAYING:
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.media_toggle_playback())
|
||||
self._attr_state = MediaPlayerState.PAUSED
|
||||
|
@ -143,12 +143,12 @@ class TeslemetryMediaEntity(TeslemetryVehicleEntity, MediaPlayerEntity):
|
|||
|
||||
async def async_media_next_track(self) -> None:
|
||||
"""Send next track command."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
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()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.media_prev_track())
|
||||
|
|
|
@ -164,7 +164,7 @@ class TeslemetryVehicleNumberEntity(TeslemetryVehicleEntity, NumberEntity):
|
|||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Set new value."""
|
||||
value = int(value)
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(self.entity_description.scopes[0])
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.entity_description.func(self.api, value))
|
||||
self._attr_native_value = value
|
||||
|
@ -200,7 +200,7 @@ class TeslemetryEnergyInfoNumberSensorEntity(TeslemetryEnergyInfoEntity, NumberE
|
|||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Set new value."""
|
||||
value = int(value)
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
await handle_command(self.entity_description.func(self.api, value))
|
||||
self._attr_native_value = value
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -144,7 +144,7 @@ class TeslemetrySeatHeaterSelectEntity(TeslemetryVehicleEntity, SelectEntity):
|
|||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
level = self._attr_options.index(option)
|
||||
# AC must be on to turn on seat heater
|
||||
|
@ -189,7 +189,7 @@ class TeslemetryWheelHeaterSelectEntity(TeslemetryVehicleEntity, SelectEntity):
|
|||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.VEHICLE_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
level = self._attr_options.index(option)
|
||||
# AC must be on to turn on steering wheel heater
|
||||
|
@ -226,7 +226,7 @@ class TeslemetryOperationSelectEntity(TeslemetryEnergyInfoEntity, SelectEntity):
|
|||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
await handle_command(self.api.operation(option))
|
||||
self._attr_current_option = option
|
||||
self.async_write_ha_state()
|
||||
|
@ -256,7 +256,7 @@ class TeslemetryExportRuleSelectEntity(TeslemetryEnergyInfoEntity, SelectEntity)
|
|||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
await handle_command(
|
||||
self.api.grid_import_export(customer_preferred_export_rule=option)
|
||||
)
|
||||
|
|
|
@ -567,8 +567,26 @@
|
|||
"no_energy_site_data_for_device": {
|
||||
"message": "No energy site data for device ID: {device_id}"
|
||||
},
|
||||
"command_exception": {
|
||||
"message": "Command returned exception: {message}"
|
||||
},
|
||||
"command_error": {
|
||||
"message": "Command returned error: {error}"
|
||||
},
|
||||
"command_reason": {
|
||||
"message": "Command was rejected: {reason}"
|
||||
},
|
||||
"command_no_result": {
|
||||
"message": "Command had no result"
|
||||
},
|
||||
"wake_up_failed": {
|
||||
"message": "Failed to wake up vehicle: {message}"
|
||||
},
|
||||
"wake_up_timeout": {
|
||||
"message": "Timed out trying to wake up vehicle"
|
||||
},
|
||||
"missing_scope": {
|
||||
"message": "Missing required scope: {scope}"
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
|
|
|
@ -157,7 +157,7 @@ class TeslemetryVehicleSwitchEntity(TeslemetryVehicleEntity, TeslemetrySwitchEnt
|
|||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on the Switch."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(self.entity_description.scopes[0])
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.entity_description.on_func(self.api))
|
||||
self._attr_is_on = True
|
||||
|
@ -165,7 +165,7 @@ class TeslemetryVehicleSwitchEntity(TeslemetryVehicleEntity, TeslemetrySwitchEnt
|
|||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the Switch."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(self.entity_description.scopes[0])
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.entity_description.off_func(self.api))
|
||||
self._attr_is_on = False
|
||||
|
@ -207,7 +207,7 @@ class TeslemetryChargeFromGridSwitchEntity(
|
|||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on the Switch."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
await handle_command(
|
||||
self.api.grid_import_export(
|
||||
disallow_charge_from_grid_with_solar_installed=False
|
||||
|
@ -218,7 +218,7 @@ class TeslemetryChargeFromGridSwitchEntity(
|
|||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn off the Switch."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
await handle_command(
|
||||
self.api.grid_import_export(
|
||||
disallow_charge_from_grid_with_solar_installed=True
|
||||
|
@ -249,14 +249,14 @@ class TeslemetryStormModeSwitchEntity(
|
|||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on the Switch."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
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()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
await handle_command(self.api.storm_mode(enabled=False))
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -103,7 +103,7 @@ class TeslemetryUpdateEntity(TeslemetryVehicleEntity, UpdateEntity):
|
|||
self, version: str | None, backup: bool, **kwargs: Any
|
||||
) -> None:
|
||||
"""Install an update."""
|
||||
self.raise_for_scope()
|
||||
self.raise_for_scope(Scope.ENERGY_CMDS)
|
||||
await self.wake_up_if_asleep()
|
||||
await handle_vehicle_command(self.api.schedule_software_update(offset_sec=60))
|
||||
self._attr_in_progress = True
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
from unittest.mock import patch
|
||||
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.teslemetry.const import DOMAIN
|
||||
from homeassistant.const import Platform
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
# serializer version: 1
|
||||
# name: test_asleep_or_offline[HomeAssistantError]
|
||||
'Timed out trying to wake up vehicle'
|
||||
# ---
|
||||
# name: test_asleep_or_offline[InvalidCommand]
|
||||
'Failed to wake up vehicle: The data request or command is unknown.'
|
||||
# ---
|
||||
# name: test_climate[climate.test_cabin_overheat_protection-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
@ -499,3 +505,6 @@
|
|||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_invalid_error[error]
|
||||
'Command returned exception: The data request or command is unknown.'
|
||||
# ---
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
"""Test the Teslemetry binary sensor platform."""
|
||||
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.components.teslemetry.coordinator import VEHICLE_INTERVAL
|
||||
|
@ -33,7 +35,7 @@ async def test_binary_sensor_refresh(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Tests that the binary sensor entities are correct."""
|
||||
|
@ -51,7 +53,7 @@ async def test_binary_sensor_refresh(
|
|||
|
||||
async def test_binary_sensor_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the binary sensor entities are correct when offline."""
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
|
|
|
@ -4,7 +4,7 @@ from unittest.mock import AsyncMock, patch
|
|||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import InvalidCommand, VehicleOffline
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
|
@ -196,7 +196,7 @@ async def test_climate_alt(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the climate entity is correct."""
|
||||
|
||||
|
@ -210,7 +210,7 @@ async def test_climate_offline(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the climate entity is correct."""
|
||||
|
||||
|
@ -219,7 +219,7 @@ async def test_climate_offline(
|
|||
assert_entities(hass, entry.entry_id, entity_registry, snapshot)
|
||||
|
||||
|
||||
async def test_invalid_error(hass: HomeAssistant) -> None:
|
||||
async def test_invalid_error(hass: HomeAssistant, snapshot: SnapshotAssertion) -> None:
|
||||
"""Tests service error is handled."""
|
||||
|
||||
await setup_platform(hass, platforms=[Platform.CLIMATE])
|
||||
|
@ -239,10 +239,7 @@ async def test_invalid_error(hass: HomeAssistant) -> None:
|
|||
blocking=True,
|
||||
)
|
||||
mock_on.assert_called_once()
|
||||
assert (
|
||||
str(error.value)
|
||||
== "Teslemetry command failed, The data request or command is unknown."
|
||||
)
|
||||
assert str(error.value) == snapshot(name="error")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("response", COMMAND_ERRORS)
|
||||
|
@ -291,10 +288,11 @@ async def test_ignored_error(
|
|||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_asleep_or_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_wake_up,
|
||||
mock_vehicle,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
mock_wake_up: AsyncMock,
|
||||
mock_vehicle: AsyncMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
"""Tests asleep is handled."""
|
||||
|
||||
|
@ -320,7 +318,7 @@ async def test_asleep_or_offline(
|
|||
{ATTR_ENTITY_ID: [entity_id]},
|
||||
blocking=True,
|
||||
)
|
||||
assert str(error.value) == "The data request or command is unknown."
|
||||
assert str(error.value) == snapshot(name="InvalidCommand")
|
||||
mock_wake_up.assert_called_once()
|
||||
|
||||
mock_wake_up.side_effect = None
|
||||
|
@ -339,7 +337,7 @@ async def test_asleep_or_offline(
|
|||
{ATTR_ENTITY_ID: [entity_id]},
|
||||
blocking=True,
|
||||
)
|
||||
assert str(error.value) == "Could not wake up vehicle"
|
||||
assert str(error.value) == snapshot(name="HomeAssistantError")
|
||||
mock_wake_up.assert_called_once()
|
||||
mock_vehicle.assert_called()
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Test the Teslemetry config flow."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from aiohttp import ClientConnectionError
|
||||
import pytest
|
||||
|
@ -60,7 +60,10 @@ async def test_form(
|
|||
],
|
||||
)
|
||||
async def test_form_errors(
|
||||
hass: HomeAssistant, side_effect, error, mock_metadata
|
||||
hass: HomeAssistant,
|
||||
side_effect: TeslaFleetError,
|
||||
error: dict[str, str],
|
||||
mock_metadata: AsyncMock,
|
||||
) -> None:
|
||||
"""Test errors are handled."""
|
||||
|
||||
|
@ -86,7 +89,7 @@ async def test_form_errors(
|
|||
assert result3["type"] is FlowResultType.CREATE_ENTRY
|
||||
|
||||
|
||||
async def test_reauth(hass: HomeAssistant, mock_metadata) -> None:
|
||||
async def test_reauth(hass: HomeAssistant, mock_metadata: AsyncMock) -> None:
|
||||
"""Test reauth flow."""
|
||||
|
||||
mock_entry = MockConfigEntry(
|
||||
|
@ -127,7 +130,10 @@ async def test_reauth(hass: HomeAssistant, mock_metadata) -> None:
|
|||
],
|
||||
)
|
||||
async def test_reauth_errors(
|
||||
hass: HomeAssistant, mock_metadata, side_effect, error
|
||||
hass: HomeAssistant,
|
||||
mock_metadata: AsyncMock,
|
||||
side_effect: TeslaFleetError,
|
||||
error: dict[str, str],
|
||||
) -> None:
|
||||
"""Test reauth flows that fail."""
|
||||
|
||||
|
@ -178,7 +184,7 @@ async def test_unique_id_abort(
|
|||
assert result2["type"] is FlowResultType.ABORT
|
||||
|
||||
|
||||
async def test_migrate_from_1_1(hass: HomeAssistant, mock_metadata) -> None:
|
||||
async def test_migrate_from_1_1(hass: HomeAssistant, mock_metadata: AsyncMock) -> None:
|
||||
"""Test config migration."""
|
||||
|
||||
mock_entry = MockConfigEntry(
|
||||
|
@ -199,7 +205,9 @@ async def test_migrate_from_1_1(hass: HomeAssistant, mock_metadata) -> None:
|
|||
assert entry.unique_id == METADATA["uid"]
|
||||
|
||||
|
||||
async def test_migrate_error_from_1_1(hass: HomeAssistant, mock_metadata) -> None:
|
||||
async def test_migrate_error_from_1_1(
|
||||
hass: HomeAssistant, mock_metadata: AsyncMock
|
||||
) -> None:
|
||||
"""Test config migration handles errors."""
|
||||
|
||||
mock_metadata.side_effect = TeslaFleetError
|
||||
|
@ -220,7 +228,9 @@ async def test_migrate_error_from_1_1(hass: HomeAssistant, mock_metadata) -> Non
|
|||
assert entry.state is ConfigEntryState.MIGRATION_ERROR
|
||||
|
||||
|
||||
async def test_migrate_error_from_future(hass: HomeAssistant, mock_metadata) -> None:
|
||||
async def test_migrate_error_from_future(
|
||||
hass: HomeAssistant, mock_metadata: AsyncMock
|
||||
) -> None:
|
||||
"""Test a future version isn't migrated."""
|
||||
|
||||
mock_metadata.side_effect = TeslaFleetError
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""Test the Teslemetry cover platform."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
|
@ -43,7 +43,7 @@ async def test_cover_alt(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the cover entities are correct with alternate values."""
|
||||
|
||||
|
@ -57,7 +57,7 @@ async def test_cover_noscope(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_metadata,
|
||||
mock_metadata: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the cover entities are correct without scopes."""
|
||||
|
||||
|
@ -68,7 +68,7 @@ async def test_cover_noscope(
|
|||
|
||||
async def test_cover_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the cover entities are correct when offline."""
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"""Test the Teslemetry device tracker platform."""
|
||||
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.const import STATE_UNKNOWN, Platform
|
||||
|
|
|
@ -4,7 +4,7 @@ from unittest.mock import AsyncMock
|
|||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import (
|
||||
InvalidToken,
|
||||
SubscriptionRequired,
|
||||
|
@ -48,7 +48,10 @@ async def test_load_unload(hass: HomeAssistant) -> None:
|
|||
|
||||
@pytest.mark.parametrize(("side_effect", "state"), ERRORS)
|
||||
async def test_init_error(
|
||||
hass: HomeAssistant, mock_products, side_effect, state
|
||||
hass: HomeAssistant,
|
||||
mock_products: AsyncMock,
|
||||
side_effect: TeslaFleetError,
|
||||
state: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test init with errors."""
|
||||
|
||||
|
@ -86,7 +89,7 @@ async def test_vehicle_refresh_asleep(
|
|||
|
||||
|
||||
async def test_vehicle_refresh_offline(
|
||||
hass: HomeAssistant, mock_vehicle_data, freezer: FrozenDateTimeFactory
|
||||
hass: HomeAssistant, mock_vehicle_data: AsyncMock, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Test coordinator refresh with an error."""
|
||||
entry = await setup_platform(hass, [Platform.CLIMATE])
|
||||
|
@ -103,7 +106,10 @@ async def test_vehicle_refresh_offline(
|
|||
|
||||
@pytest.mark.parametrize(("side_effect", "state"), ERRORS)
|
||||
async def test_vehicle_refresh_error(
|
||||
hass: HomeAssistant, mock_vehicle_data, side_effect, state
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
side_effect: TeslaFleetError,
|
||||
state: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test coordinator refresh with an error."""
|
||||
mock_vehicle_data.side_effect = side_effect
|
||||
|
@ -112,7 +118,7 @@ async def test_vehicle_refresh_error(
|
|||
|
||||
|
||||
async def test_vehicle_sleep(
|
||||
hass: HomeAssistant, mock_vehicle_data, freezer: FrozenDateTimeFactory
|
||||
hass: HomeAssistant, mock_vehicle_data: AsyncMock, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Test coordinator refresh with an error."""
|
||||
await setup_platform(hass, [Platform.CLIMATE])
|
||||
|
@ -171,7 +177,10 @@ async def test_vehicle_sleep(
|
|||
# Test Energy Live Coordinator
|
||||
@pytest.mark.parametrize(("side_effect", "state"), ERRORS)
|
||||
async def test_energy_live_refresh_error(
|
||||
hass: HomeAssistant, mock_live_status, side_effect, state
|
||||
hass: HomeAssistant,
|
||||
mock_live_status: AsyncMock,
|
||||
side_effect: TeslaFleetError,
|
||||
state: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test coordinator refresh with an error."""
|
||||
mock_live_status.side_effect = side_effect
|
||||
|
@ -182,7 +191,10 @@ async def test_energy_live_refresh_error(
|
|||
# Test Energy Site Coordinator
|
||||
@pytest.mark.parametrize(("side_effect", "state"), ERRORS)
|
||||
async def test_energy_site_refresh_error(
|
||||
hass: HomeAssistant, mock_site_info, side_effect, state
|
||||
hass: HomeAssistant,
|
||||
mock_site_info: AsyncMock,
|
||||
side_effect: TeslaFleetError,
|
||||
state: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test coordinator refresh with an error."""
|
||||
mock_site_info.side_effect = side_effect
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""Test the Teslemetry lock platform."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.components.lock import (
|
||||
|
@ -34,7 +34,7 @@ async def test_lock(
|
|||
|
||||
async def test_lock_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the lock entities are correct when offline."""
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
"""Test the Teslemetry media player platform."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.components.media_player import (
|
||||
|
@ -38,7 +38,7 @@ async def test_media_player_alt(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the media player entities are correct."""
|
||||
|
||||
|
@ -49,7 +49,7 @@ async def test_media_player_alt(
|
|||
|
||||
async def test_media_player_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the media player entities are correct when offline."""
|
||||
|
||||
|
@ -63,7 +63,7 @@ async def test_media_player_noscope(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_metadata,
|
||||
mock_metadata: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the media player entities are correct without required scope."""
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""Test the Teslemetry number platform."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.components.number import (
|
||||
|
@ -33,7 +33,7 @@ async def test_number(
|
|||
|
||||
async def test_number_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the number entities are correct when offline."""
|
||||
|
||||
|
@ -44,7 +44,9 @@ async def test_number_offline(
|
|||
|
||||
|
||||
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
|
||||
async def test_number_services(hass: HomeAssistant, mock_vehicle_data) -> None:
|
||||
async def test_number_services(
|
||||
hass: HomeAssistant, mock_vehicle_data: AsyncMock
|
||||
) -> None:
|
||||
"""Tests that the number services work."""
|
||||
mock_vehicle_data.return_value = VEHICLE_DATA_ALT
|
||||
await setup_platform(hass, [Platform.NUMBER])
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""Test the Teslemetry select platform."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.const import EnergyExportMode, EnergyOperationMode
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
|
@ -35,7 +35,7 @@ async def test_select(
|
|||
|
||||
async def test_select_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the select entities are correct when offline."""
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
"""Test the Teslemetry sensor platform."""
|
||||
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.teslemetry.coordinator import VEHICLE_INTERVAL
|
||||
from homeassistant.const import Platform
|
||||
|
@ -21,7 +23,7 @@ async def test_sensors(
|
|||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the sensor entities are correct."""
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
"""Test the Teslemetry switch platform."""
|
||||
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.components.switch import (
|
||||
|
@ -40,7 +40,7 @@ async def test_switch_alt(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the switch entities are correct."""
|
||||
|
||||
|
@ -51,7 +51,7 @@ async def test_switch_alt(
|
|||
|
||||
async def test_switch_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the switch entities are correct when offline."""
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
"""Test the Teslemetry update platform."""
|
||||
|
||||
import copy
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from syrupy import SnapshotAssertion
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tesla_fleet_api.exceptions import VehicleOffline
|
||||
|
||||
from homeassistant.components.teslemetry.coordinator import VEHICLE_INTERVAL
|
||||
|
@ -35,7 +35,7 @@ async def test_update_alt(
|
|||
hass: HomeAssistant,
|
||||
snapshot: SnapshotAssertion,
|
||||
entity_registry: er.EntityRegistry,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the update entities are correct."""
|
||||
|
||||
|
@ -46,7 +46,7 @@ async def test_update_alt(
|
|||
|
||||
async def test_update_offline(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
) -> None:
|
||||
"""Tests that the update entities are correct when offline."""
|
||||
|
||||
|
@ -58,7 +58,7 @@ async def test_update_offline(
|
|||
|
||||
async def test_update_services(
|
||||
hass: HomeAssistant,
|
||||
mock_vehicle_data,
|
||||
mock_vehicle_data: AsyncMock,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
snapshot: SnapshotAssertion,
|
||||
) -> None:
|
||||
|
|
Loading…
Reference in New Issue