Skip to content

Commit

Permalink
Check Tessie scopes to fix startup bug (#120710)
Browse files Browse the repository at this point in the history
* Add scope check

* Add tests

* Bump Teslemetry
  • Loading branch information
Bre77 committed Jun 28, 2024
1 parent 6d93695 commit 3d58025
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 36 deletions.
2 changes: 1 addition & 1 deletion homeassistant/components/teslemetry/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
"iot_class": "cloud_polling",
"loggers": ["tesla-fleet-api"],
"quality_scale": "platinum",
"requirements": ["tesla-fleet-api==0.6.1"]
"requirements": ["tesla-fleet-api==0.6.2"]
}
68 changes: 38 additions & 30 deletions homeassistant/components/tessie/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from aiohttp import ClientError, ClientResponseError
from tesla_fleet_api import EnergySpecific, Tessie
from tesla_fleet_api.const import Scope
from tesla_fleet_api.exceptions import TeslaFleetError
from tessie_api import get_state_of_all_vehicles

Expand Down Expand Up @@ -94,41 +95,48 @@ async def async_setup_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bo

# Energy Sites
tessie = Tessie(session, api_key)
energysites: list[TessieEnergyData] = []

try:
products = (await tessie.products())["response"]
scopes = await tessie.scopes()
except TeslaFleetError as e:
raise ConfigEntryNotReady from e

energysites: list[TessieEnergyData] = []
for product in products:
if "energy_site_id" in product:
site_id = product["energy_site_id"]
api = EnergySpecific(tessie.energy, site_id)
energysites.append(
TessieEnergyData(
api=api,
id=site_id,
live_coordinator=TessieEnergySiteLiveCoordinator(hass, api),
info_coordinator=TessieEnergySiteInfoCoordinator(hass, api),
device=DeviceInfo(
identifiers={(DOMAIN, str(site_id))},
manufacturer="Tesla",
name=product.get("site_name", "Energy Site"),
),
if Scope.ENERGY_DEVICE_DATA in scopes:
try:
products = (await tessie.products())["response"]
except TeslaFleetError as e:
raise ConfigEntryNotReady from e

for product in products:
if "energy_site_id" in product:
site_id = product["energy_site_id"]
api = EnergySpecific(tessie.energy, site_id)
energysites.append(
TessieEnergyData(
api=api,
id=site_id,
live_coordinator=TessieEnergySiteLiveCoordinator(hass, api),
info_coordinator=TessieEnergySiteInfoCoordinator(hass, api),
device=DeviceInfo(
identifiers={(DOMAIN, str(site_id))},
manufacturer="Tesla",
name=product.get("site_name", "Energy Site"),
),
)
)
)

# Populate coordinator data before forwarding to platforms
await asyncio.gather(
*(
energysite.live_coordinator.async_config_entry_first_refresh()
for energysite in energysites
),
*(
energysite.info_coordinator.async_config_entry_first_refresh()
for energysite in energysites
),
)

# Populate coordinator data before forwarding to platforms
await asyncio.gather(
*(
energysite.live_coordinator.async_config_entry_first_refresh()
for energysite in energysites
),
*(
energysite.info_coordinator.async_config_entry_first_refresh()
for energysite in energysites
),
)

entry.runtime_data = TessieData(vehicles, energysites)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/tessie/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/tessie",
"iot_class": "cloud_polling",
"loggers": ["tessie"],
"requirements": ["tessie-api==0.0.9", "tesla-fleet-api==0.6.1"]
"requirements": ["tessie-api==0.0.9", "tesla-fleet-api==0.6.2"]
}
2 changes: 1 addition & 1 deletion requirements_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2711,7 +2711,7 @@ temperusb==1.6.1

# homeassistant.components.teslemetry
# homeassistant.components.tessie
tesla-fleet-api==0.6.1
tesla-fleet-api==0.6.2

# homeassistant.components.powerwall
tesla-powerwall==0.5.2
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2109,7 +2109,7 @@ temperusb==1.6.1

# homeassistant.components.teslemetry
# homeassistant.components.tessie
tesla-fleet-api==0.6.1
tesla-fleet-api==0.6.2

# homeassistant.components.powerwall
tesla-powerwall==0.5.2
Expand Down
11 changes: 11 additions & 0 deletions tests/components/tessie/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@
SITE_INFO = load_json_object_fixture("site_info.json", DOMAIN)
RESPONSE_OK = {"response": {}, "error": None}
COMMAND_OK = {"response": {"result": True, "reason": ""}}
SCOPES = [
"user_data",
"vehicle_device_data",
"vehicle_cmds",
"vehicle_charging_cmds",
"energy_device_data",
"energy_cmds",
"offline_access",
"openid",
]
NO_SCOPES = ["user_data", "offline_access", "openid"]


async def setup_platform(
Expand Down
11 changes: 11 additions & 0 deletions tests/components/tessie/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
COMMAND_OK,
LIVE_STATUS,
PRODUCTS,
SCOPES,
SITE_INFO,
TEST_STATE_OF_ALL_VEHICLES,
TEST_VEHICLE_STATE_ONLINE,
Expand Down Expand Up @@ -51,6 +52,16 @@ def mock_get_state_of_all_vehicles():


# Fleet API
@pytest.fixture(autouse=True)
def mock_scopes():
"""Mock scopes function."""
with patch(
"homeassistant.components.tessie.Tessie.scopes",
return_value=SCOPES,
) as mock_scopes:
yield mock_scopes


@pytest.fixture(autouse=True)
def mock_products():
"""Mock Tesla Fleet Api products method."""
Expand Down
14 changes: 12 additions & 2 deletions tests/components/tessie/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,21 @@ async def test_connection_failure(
assert entry.state is ConfigEntryState.SETUP_RETRY


async def test_fleet_error(hass: HomeAssistant) -> None:
"""Test init with a fleet error."""
async def test_products_error(hass: HomeAssistant) -> None:
"""Test init with a fleet error on products."""

with patch(
"homeassistant.components.tessie.Tessie.products", side_effect=TeslaFleetError
):
entry = await setup_platform(hass)
assert entry.state is ConfigEntryState.SETUP_RETRY


async def test_scopes_error(hass: HomeAssistant) -> None:
"""Test init with a fleet error on scopes."""

with patch(
"homeassistant.components.tessie.Tessie.scopes", side_effect=TeslaFleetError
):
entry = await setup_platform(hass)
assert entry.state is ConfigEntryState.SETUP_RETRY

0 comments on commit 3d58025

Please sign in to comment.