Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions homeassistant/components/teslemetry/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import asyncio
from typing import Any

from tesla_fleet_api.exceptions import TeslaFleetError

from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity

Expand Down Expand Up @@ -45,11 +48,22 @@ def __init__(
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:
state = (await self.api.wake_up())["response"]["state"]
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:
await asyncio.sleep(5)
times += 1
if times >= 4: # Give up after 30 seconds total
raise HomeAssistantError("Could not wake up vehicle")
await asyncio.sleep(times * 5)

def get(self, key: str | None = None, default: Any | None = None) -> Any:
"""Return a specific value from coordinator data."""
Expand Down
10 changes: 10 additions & 0 deletions tests/components/teslemetry/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ def mock_wake_up():
yield mock_wake_up


@pytest.fixture(autouse=True)
def mock_vehicle():
"""Mock Tesla Fleet API Vehicle Specific vehicle method."""
with patch(
"homeassistant.components.teslemetry.VehicleSpecific.vehicle",
return_value=WAKE_UP_ONLINE,
) as mock_vehicle:
yield mock_vehicle


@pytest.fixture(autouse=True)
def mock_request():
"""Mock Tesla Fleet API Vehicle Specific class."""
Expand Down
47 changes: 45 additions & 2 deletions tests/components/teslemetry/test_climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from homeassistant.helpers import entity_registry as er

from . import assert_entities, setup_platform
from .const import WAKE_UP_ASLEEP, WAKE_UP_ONLINE

from tests.common import async_fire_time_changed

Expand Down Expand Up @@ -108,7 +109,11 @@ async def test_errors(


async def test_asleep_or_offline(
hass: HomeAssistant, mock_vehicle_data, freezer: FrozenDateTimeFactory
hass: HomeAssistant,
mock_vehicle_data,
mock_wake_up,
mock_vehicle,
freezer: FrozenDateTimeFactory,
) -> None:
"""Tests asleep is handled."""

Expand All @@ -123,9 +128,47 @@ async def test_asleep_or_offline(
async_fire_time_changed(hass)
await hass.async_block_till_done()
mock_vehicle_data.assert_called_once()
mock_wake_up.reset_mock()

# Run a command but fail trying to wake up the vehicle
mock_wake_up.side_effect = InvalidCommand
with pytest.raises(HomeAssistantError) as error:
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: [entity_id]},
blocking=True,
)
assert error
mock_wake_up.assert_called_once()

mock_wake_up.side_effect = None
mock_wake_up.reset_mock()

# Run a command but timeout trying to wake up the vehicle
mock_wake_up.return_value = WAKE_UP_ASLEEP
mock_vehicle.return_value = WAKE_UP_ASLEEP
with patch(
"homeassistant.components.teslemetry.entity.asyncio.sleep"
), pytest.raises(HomeAssistantError) as error:
await hass.services.async_call(
CLIMATE_DOMAIN,
SERVICE_TURN_ON,
{ATTR_ENTITY_ID: [entity_id]},
blocking=True,
)
assert error
mock_wake_up.assert_called_once()
mock_vehicle.assert_called()

mock_wake_up.reset_mock()
mock_vehicle.reset_mock()
mock_wake_up.return_value = WAKE_UP_ONLINE
mock_vehicle.return_value = WAKE_UP_ONLINE

# Run a command that will wake up the vehicle, but not immediately
# Run a command and wake up the vehicle immediately
await hass.services.async_call(
CLIMATE_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: [entity_id]}, blocking=True
)
await hass.async_block_till_done()
mock_wake_up.assert_called_once()