Revert powerwall back to awaiting each api call (#110947)

We converted these to run as tasks in the hope that it would be faster,
but since the cost of establishing another connection and the task
overhead exceeded the savings, it makes sense to await them all in
series.
This commit is contained in:
J. Nick Koston 2024-02-19 13:13:49 -06:00 committed by GitHub
parent 058eec114b
commit 1bc0263ea4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,7 +1,6 @@
"""The Tesla Powerwall integration.""" """The Tesla Powerwall integration."""
from __future__ import annotations from __future__ import annotations
import asyncio
from contextlib import AsyncExitStack from contextlib import AsyncExitStack
from datetime import timedelta from datetime import timedelta
import logging import logging
@ -221,35 +220,26 @@ async def _login_and_fetch_base_info(
async def _call_base_info(power_wall: Powerwall, host: str) -> PowerwallBaseInfo: async def _call_base_info(power_wall: Powerwall, host: str) -> PowerwallBaseInfo:
"""Return PowerwallBaseInfo for the device.""" """Return PowerwallBaseInfo for the device."""
# We await each call individually since the powerwall
try: # supports http keep-alive and we want to reuse the connection
async with asyncio.TaskGroup() as tg: # as its faster than establishing a new connection when
gateway_din = tg.create_task(power_wall.get_gateway_din()) # run concurrently.
site_info = tg.create_task(power_wall.get_site_info()) gateway_din = await power_wall.get_gateway_din()
status = tg.create_task(power_wall.get_status()) site_info = await power_wall.get_site_info()
device_type = tg.create_task(power_wall.get_device_type()) status = await power_wall.get_status()
serial_numbers = tg.create_task(power_wall.get_serial_numbers()) device_type = await power_wall.get_device_type()
batteries = tg.create_task(power_wall.get_batteries()) serial_numbers = await power_wall.get_serial_numbers()
batteries = await power_wall.get_batteries()
# Mimic the behavior of asyncio.gather by reraising the first caught exception since
# this is what is expected by the caller of this method
#
# While it would have been cleaner to use asyncio.gather in the first place instead of
# TaskGroup but in cases where you have more than 6 tasks, the linter fails due to
# missing typing information.
except BaseExceptionGroup as e:
raise e.exceptions[0] from None
# Serial numbers MUST be sorted to ensure the unique_id is always the same # Serial numbers MUST be sorted to ensure the unique_id is always the same
# for backwards compatibility. # for backwards compatibility.
return PowerwallBaseInfo( return PowerwallBaseInfo(
gateway_din=gateway_din.result().upper(), gateway_din=gateway_din,
site_info=site_info.result(), site_info=site_info,
status=status.result(), status=status,
device_type=device_type.result(), device_type=device_type,
serial_numbers=sorted(serial_numbers.result()), serial_numbers=sorted(serial_numbers),
url=f"https://{host}", url=f"https://{host}",
batteries={battery.serial_number: battery for battery in batteries.result()}, batteries={battery.serial_number: battery for battery in batteries},
) )
@ -263,34 +253,25 @@ async def get_backup_reserve_percentage(power_wall: Powerwall) -> Optional[float
async def _fetch_powerwall_data(power_wall: Powerwall) -> PowerwallData: async def _fetch_powerwall_data(power_wall: Powerwall) -> PowerwallData:
"""Process and update powerwall data.""" """Process and update powerwall data."""
# We await each call individually since the powerwall
try: # supports http keep-alive and we want to reuse the connection
async with asyncio.TaskGroup() as tg: # as its faster than establishing a new connection when
backup_reserve = tg.create_task(get_backup_reserve_percentage(power_wall)) # run concurrently.
charge = tg.create_task(power_wall.get_charge()) backup_reserve = await get_backup_reserve_percentage(power_wall)
site_master = tg.create_task(power_wall.get_sitemaster()) charge = await power_wall.get_charge()
meters = tg.create_task(power_wall.get_meters()) site_master = await power_wall.get_sitemaster()
grid_services_active = tg.create_task(power_wall.is_grid_services_active()) meters = await power_wall.get_meters()
grid_status = tg.create_task(power_wall.get_grid_status()) grid_services_active = await power_wall.is_grid_services_active()
batteries = tg.create_task(power_wall.get_batteries()) grid_status = await power_wall.get_grid_status()
batteries = await power_wall.get_batteries()
# Mimic the behavior of asyncio.gather by reraising the first caught exception since
# this is what is expected by the caller of this method
#
# While it would have been cleaner to use asyncio.gather in the first place instead of
# TaskGroup but in cases where you have more than 6 tasks, the linter fails due to
# missing typing information.
except BaseExceptionGroup as e:
raise e.exceptions[0] from None
return PowerwallData( return PowerwallData(
charge=charge.result(), charge=charge,
site_master=site_master.result(), site_master=site_master,
meters=meters.result(), meters=meters,
grid_services_active=grid_services_active.result(), grid_services_active=grid_services_active,
grid_status=grid_status.result(), grid_status=grid_status,
backup_reserve=backup_reserve.result(), backup_reserve=backup_reserve,
batteries={battery.serial_number: battery for battery in batteries.result()}, batteries={battery.serial_number: battery for battery in batteries},
) )