Cleanup nest async methods that do not need to actually await (#72170)

Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>
This commit is contained in:
Allen Porter 2022-05-20 07:47:18 -07:00 committed by GitHub
parent d459a5c66e
commit 775be354a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 43 additions and 97 deletions

View file

@ -54,6 +54,7 @@ from . import api, config_flow
from .const import ( from .const import (
CONF_PROJECT_ID, CONF_PROJECT_ID,
CONF_SUBSCRIBER_ID, CONF_SUBSCRIBER_ID,
DATA_DEVICE_MANAGER,
DATA_NEST_CONFIG, DATA_NEST_CONFIG,
DATA_SDM, DATA_SDM,
DATA_SUBSCRIBER, DATA_SUBSCRIBER,
@ -63,8 +64,8 @@ from .events import EVENT_NAME_MAP, NEST_EVENT
from .legacy import async_setup_legacy, async_setup_legacy_entry from .legacy import async_setup_legacy, async_setup_legacy_entry
from .media_source import ( from .media_source import (
async_get_media_event_store, async_get_media_event_store,
async_get_media_source_devices,
async_get_transcoder, async_get_transcoder,
get_media_source_devices,
) )
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -205,7 +206,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
raise ConfigEntryNotReady from err raise ConfigEntryNotReady from err
try: try:
await subscriber.async_get_device_manager() device_manager = await subscriber.async_get_device_manager()
except ApiException as err: except ApiException as err:
if DATA_NEST_UNAVAILABLE not in hass.data[DOMAIN]: if DATA_NEST_UNAVAILABLE not in hass.data[DOMAIN]:
_LOGGER.error("Device manager error: %s", err) _LOGGER.error("Device manager error: %s", err)
@ -215,6 +216,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN].pop(DATA_NEST_UNAVAILABLE, None) hass.data[DOMAIN].pop(DATA_NEST_UNAVAILABLE, None)
hass.data[DOMAIN][DATA_SUBSCRIBER] = subscriber hass.data[DOMAIN][DATA_SUBSCRIBER] = subscriber
hass.data[DOMAIN][DATA_DEVICE_MANAGER] = device_manager
hass.config_entries.async_setup_platforms(entry, PLATFORMS) hass.config_entries.async_setup_platforms(entry, PLATFORMS)
@ -232,6 +234,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok: if unload_ok:
hass.data[DOMAIN].pop(DATA_SUBSCRIBER) hass.data[DOMAIN].pop(DATA_SUBSCRIBER)
hass.data[DOMAIN].pop(DATA_DEVICE_MANAGER)
hass.data[DOMAIN].pop(DATA_NEST_UNAVAILABLE, None) hass.data[DOMAIN].pop(DATA_NEST_UNAVAILABLE, None)
return unload_ok return unload_ok
@ -275,7 +278,7 @@ class NestEventViewBase(HomeAssistantView, ABC):
if not user.permissions.check_entity(entry.entity_id, POLICY_READ): if not user.permissions.check_entity(entry.entity_id, POLICY_READ):
raise Unauthorized(entity_id=entry.entity_id) raise Unauthorized(entity_id=entry.entity_id)
devices = await get_media_source_devices(self.hass) devices = async_get_media_source_devices(self.hass)
if not (nest_device := devices.get(device_id)): if not (nest_device := devices.get(device_id)):
return self._json_error( return self._json_error(
f"No Nest Device found for '{device_id}'", HTTPStatus.NOT_FOUND f"No Nest Device found for '{device_id}'", HTTPStatus.NOT_FOUND

View file

@ -15,19 +15,20 @@ from google_nest_sdm.camera_traits import (
StreamingProtocol, StreamingProtocol,
) )
from google_nest_sdm.device import Device from google_nest_sdm.device import Device
from google_nest_sdm.device_manager import DeviceManager
from google_nest_sdm.exceptions import ApiException from google_nest_sdm.exceptions import ApiException
from homeassistant.components.camera import Camera, CameraEntityFeature from homeassistant.components.camera import Camera, CameraEntityFeature
from homeassistant.components.camera.const import StreamType from homeassistant.components.camera.const import StreamType
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, PlatformNotReady from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
from .const import DATA_SUBSCRIBER, DOMAIN from .const import DATA_DEVICE_MANAGER, DOMAIN
from .device_info import NestDeviceInfo from .device_info import NestDeviceInfo
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -43,14 +44,7 @@ async def async_setup_sdm_entry(
) -> None: ) -> None:
"""Set up the cameras.""" """Set up the cameras."""
subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER]
try:
device_manager = await subscriber.async_get_device_manager()
except ApiException as err:
raise PlatformNotReady from err
# Fetch initial data so we have data when entities subscribe.
entities = [] entities = []
for device in device_manager.devices.values(): for device in device_manager.devices.values():
if ( if (

View file

@ -4,8 +4,8 @@ from __future__ import annotations
from typing import Any, cast from typing import Any, cast
from google_nest_sdm.device import Device from google_nest_sdm.device import Device
from google_nest_sdm.device_manager import DeviceManager
from google_nest_sdm.device_traits import FanTrait, TemperatureTrait from google_nest_sdm.device_traits import FanTrait, TemperatureTrait
from google_nest_sdm.exceptions import ApiException
from google_nest_sdm.thermostat_traits import ( from google_nest_sdm.thermostat_traits import (
ThermostatEcoTrait, ThermostatEcoTrait,
ThermostatHeatCoolTrait, ThermostatHeatCoolTrait,
@ -30,11 +30,10 @@ from homeassistant.components.climate.const import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DATA_SUBSCRIBER, DOMAIN from .const import DATA_DEVICE_MANAGER, DOMAIN
from .device_info import NestDeviceInfo from .device_info import NestDeviceInfo
# Mapping for sdm.devices.traits.ThermostatMode mode field # Mapping for sdm.devices.traits.ThermostatMode mode field
@ -80,12 +79,7 @@ async def async_setup_sdm_entry(
) -> None: ) -> None:
"""Set up the client entities.""" """Set up the client entities."""
subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER]
try:
device_manager = await subscriber.async_get_device_manager()
except ApiException as err:
raise PlatformNotReady from err
entities = [] entities = []
for device in device_manager.devices.values(): for device in device_manager.devices.values():
if ThermostatHvacTrait.NAME in device.traits: if ThermostatHvacTrait.NAME in device.traits:

View file

@ -3,6 +3,7 @@
DOMAIN = "nest" DOMAIN = "nest"
DATA_SDM = "sdm" DATA_SDM = "sdm"
DATA_SUBSCRIBER = "subscriber" DATA_SUBSCRIBER = "subscriber"
DATA_DEVICE_MANAGER = "device_manager"
DATA_NEST_CONFIG = "nest_config" DATA_NEST_CONFIG = "nest_config"
WEB_AUTH_DOMAIN = DOMAIN WEB_AUTH_DOMAIN = DOMAIN

View file

@ -1,6 +1,7 @@
"""Provides device automations for Nest.""" """Provides device automations for Nest."""
from __future__ import annotations from __future__ import annotations
from google_nest_sdm.device_manager import DeviceManager
import voluptuous as vol import voluptuous as vol
from homeassistant.components.automation import ( from homeassistant.components.automation import (
@ -20,7 +21,7 @@ from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from .const import DATA_SUBSCRIBER, DOMAIN from .const import DATA_DEVICE_MANAGER, DOMAIN
from .events import DEVICE_TRAIT_TRIGGER_MAP, NEST_EVENT from .events import DEVICE_TRAIT_TRIGGER_MAP, NEST_EVENT
DEVICE = "device" DEVICE = "device"
@ -45,14 +46,12 @@ def async_get_nest_device_id(hass: HomeAssistant, device_id: str) -> str | None:
return None return None
async def async_get_device_trigger_types( @callback
def async_get_device_trigger_types(
hass: HomeAssistant, nest_device_id: str hass: HomeAssistant, nest_device_id: str
) -> list[str]: ) -> list[str]:
"""List event triggers supported for a Nest device.""" """List event triggers supported for a Nest device."""
# All devices should have already been loaded so any failures here are device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER]
# "shouldn't happen" cases
subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER]
device_manager = await subscriber.async_get_device_manager()
if not (nest_device := device_manager.devices.get(nest_device_id)): if not (nest_device := device_manager.devices.get(nest_device_id)):
raise InvalidDeviceAutomationConfig(f"Nest device not found {nest_device_id}") raise InvalidDeviceAutomationConfig(f"Nest device not found {nest_device_id}")
@ -72,7 +71,7 @@ async def async_get_triggers(
nest_device_id = async_get_nest_device_id(hass, device_id) nest_device_id = async_get_nest_device_id(hass, device_id)
if not nest_device_id: if not nest_device_id:
raise InvalidDeviceAutomationConfig(f"Device not found {device_id}") raise InvalidDeviceAutomationConfig(f"Device not found {device_id}")
trigger_types = await async_get_device_trigger_types(hass, nest_device_id) trigger_types = async_get_device_trigger_types(hass, nest_device_id)
return [ return [
{ {
CONF_PLATFORM: DEVICE, CONF_PLATFORM: DEVICE,

View file

@ -6,43 +6,39 @@ from typing import Any
from google_nest_sdm import diagnostics from google_nest_sdm import diagnostics
from google_nest_sdm.device import Device from google_nest_sdm.device import Device
from google_nest_sdm.device_manager import DeviceManager
from google_nest_sdm.device_traits import InfoTrait from google_nest_sdm.device_traits import InfoTrait
from google_nest_sdm.exceptions import ApiException
from homeassistant.components.camera import diagnostics as camera_diagnostics from homeassistant.components.camera import diagnostics as camera_diagnostics
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.device_registry import DeviceEntry from homeassistant.helpers.device_registry import DeviceEntry
from .const import DATA_SDM, DATA_SUBSCRIBER, DOMAIN from .const import DATA_DEVICE_MANAGER, DATA_SDM, DOMAIN
REDACT_DEVICE_TRAITS = {InfoTrait.NAME} REDACT_DEVICE_TRAITS = {InfoTrait.NAME}
async def _get_nest_devices( @callback
def _async_get_nest_devices(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: ConfigEntry
) -> dict[str, Device]: ) -> dict[str, Device]:
"""Return dict of available devices.""" """Return dict of available devices."""
if DATA_SDM not in config_entry.data: if DATA_SDM not in config_entry.data:
return {} return {}
if DATA_SUBSCRIBER not in hass.data[DOMAIN]: if DATA_DEVICE_MANAGER not in hass.data[DOMAIN]:
return {} return {}
subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER]
device_manager = await subscriber.async_get_device_manager() return device_manager.devices
devices: dict[str, Device] = device_manager.devices
return devices
async def async_get_config_entry_diagnostics( async def async_get_config_entry_diagnostics(
hass: HomeAssistant, config_entry: ConfigEntry hass: HomeAssistant, config_entry: ConfigEntry
) -> dict: ) -> dict:
"""Return diagnostics for a config entry.""" """Return diagnostics for a config entry."""
try: nest_devices = _async_get_nest_devices(hass, config_entry)
nest_devices = await _get_nest_devices(hass, config_entry)
except ApiException as err:
return {"error": str(err)}
if not nest_devices: if not nest_devices:
return {} return {}
data: dict[str, Any] = { data: dict[str, Any] = {
@ -65,10 +61,7 @@ async def async_get_device_diagnostics(
device: DeviceEntry, device: DeviceEntry,
) -> dict: ) -> dict:
"""Return diagnostics for a device.""" """Return diagnostics for a device."""
try: nest_devices = _async_get_nest_devices(hass, config_entry)
nest_devices = await _get_nest_devices(hass, config_entry)
except ApiException as err:
return {"error": str(err)}
nest_device_id = next(iter(device.identifiers))[1] nest_device_id = next(iter(device.identifiers))[1]
nest_device = nest_devices.get(nest_device_id) nest_device = nest_devices.get(nest_device_id)
return nest_device.get_diagnostics() if nest_device else {} return nest_device.get_diagnostics() if nest_device else {}

View file

@ -25,6 +25,7 @@ import os
from google_nest_sdm.camera_traits import CameraClipPreviewTrait, CameraEventImageTrait from google_nest_sdm.camera_traits import CameraClipPreviewTrait, CameraEventImageTrait
from google_nest_sdm.device import Device from google_nest_sdm.device import Device
from google_nest_sdm.device_manager import DeviceManager
from google_nest_sdm.event import EventImageType, ImageEventBase from google_nest_sdm.event import EventImageType, ImageEventBase
from google_nest_sdm.event_media import ( from google_nest_sdm.event_media import (
ClipPreviewSession, ClipPreviewSession,
@ -50,13 +51,13 @@ from homeassistant.components.media_source.models import (
MediaSourceItem, MediaSourceItem,
PlayMedia, PlayMedia,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.storage import Store from homeassistant.helpers.storage import Store
from homeassistant.helpers.template import DATE_STR_FORMAT from homeassistant.helpers.template import DATE_STR_FORMAT
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from .const import DATA_SUBSCRIBER, DOMAIN from .const import DATA_DEVICE_MANAGER, DOMAIN
from .device_info import NestDeviceInfo from .device_info import NestDeviceInfo
from .events import EVENT_NAME_MAP, MEDIA_SOURCE_EVENT_TITLE_MAP from .events import EVENT_NAME_MAP, MEDIA_SOURCE_EVENT_TITLE_MAP
@ -267,13 +268,13 @@ async def async_get_media_source(hass: HomeAssistant) -> MediaSource:
return NestMediaSource(hass) return NestMediaSource(hass)
async def get_media_source_devices(hass: HomeAssistant) -> Mapping[str, Device]: @callback
def async_get_media_source_devices(hass: HomeAssistant) -> Mapping[str, Device]:
"""Return a mapping of device id to eligible Nest event media devices.""" """Return a mapping of device id to eligible Nest event media devices."""
if DATA_SUBSCRIBER not in hass.data[DOMAIN]: if DATA_DEVICE_MANAGER not in hass.data[DOMAIN]:
# Integration unloaded, or is legacy nest integration # Integration unloaded, or is legacy nest integration
return {} return {}
subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER]
device_manager = await subscriber.async_get_device_manager()
device_registry = dr.async_get(hass) device_registry = dr.async_get(hass)
devices = {} devices = {}
for device in device_manager.devices.values(): for device in device_manager.devices.values():
@ -339,7 +340,7 @@ class NestMediaSource(MediaSource):
media_id: MediaId | None = parse_media_id(item.identifier) media_id: MediaId | None = parse_media_id(item.identifier)
if not media_id: if not media_id:
raise Unresolvable("No identifier specified for MediaSourceItem") raise Unresolvable("No identifier specified for MediaSourceItem")
devices = await self.devices() devices = async_get_media_source_devices(self.hass)
if not (device := devices.get(media_id.device_id)): if not (device := devices.get(media_id.device_id)):
raise Unresolvable( raise Unresolvable(
"Unable to find device with identifier: %s" % item.identifier "Unable to find device with identifier: %s" % item.identifier
@ -376,7 +377,7 @@ class NestMediaSource(MediaSource):
_LOGGER.debug( _LOGGER.debug(
"Browsing media for identifier=%s, media_id=%s", item.identifier, media_id "Browsing media for identifier=%s, media_id=%s", item.identifier, media_id
) )
devices = await self.devices() devices = async_get_media_source_devices(self.hass)
if media_id is None: if media_id is None:
# Browse the root and return child devices # Browse the root and return child devices
browse_root = _browse_root() browse_root = _browse_root()
@ -443,10 +444,6 @@ class NestMediaSource(MediaSource):
) )
return _browse_image_event(media_id, device, single_image) return _browse_image_event(media_id, device, single_image)
async def devices(self) -> Mapping[str, Device]:
"""Return all event media related devices."""
return await get_media_source_devices(self.hass)
async def _async_get_clip_preview_sessions( async def _async_get_clip_preview_sessions(
device: Device, device: Device,

View file

@ -4,8 +4,8 @@ from __future__ import annotations
import logging import logging
from google_nest_sdm.device import Device from google_nest_sdm.device import Device
from google_nest_sdm.device_manager import DeviceManager
from google_nest_sdm.device_traits import HumidityTrait, TemperatureTrait from google_nest_sdm.device_traits import HumidityTrait, TemperatureTrait
from google_nest_sdm.exceptions import ApiException
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
SensorDeviceClass, SensorDeviceClass,
@ -15,10 +15,9 @@ from homeassistant.components.sensor import (
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS from homeassistant.const import PERCENTAGE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import PlatformNotReady
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DATA_SUBSCRIBER, DOMAIN from .const import DATA_DEVICE_MANAGER, DOMAIN
from .device_info import NestDeviceInfo from .device_info import NestDeviceInfo
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -37,13 +36,7 @@ async def async_setup_sdm_entry(
) -> None: ) -> None:
"""Set up the sensors.""" """Set up the sensors."""
subscriber = hass.data[DOMAIN][DATA_SUBSCRIBER] device_manager: DeviceManager = hass.data[DOMAIN][DATA_DEVICE_MANAGER]
try:
device_manager = await subscriber.async_get_device_manager()
except ApiException as err:
_LOGGER.warning("Failed to get devices: %s", err)
raise PlatformNotReady from err
entities: list[SensorEntity] = [] entities: list[SensorEntity] = []
for device in device_manager.devices.values(): for device in device_manager.devices.values():
if TemperatureTrait.NAME in device.traits: if TemperatureTrait.NAME in device.traits:

View file

@ -2,7 +2,7 @@
from unittest.mock import patch from unittest.mock import patch
from google_nest_sdm.exceptions import ApiException, SubscriberException from google_nest_sdm.exceptions import SubscriberException
import pytest import pytest
from homeassistant.components.nest.const import DOMAIN from homeassistant.components.nest.const import DOMAIN
@ -139,34 +139,6 @@ async def test_setup_susbcriber_failure(
assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {} assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == {}
async def test_device_manager_failure(
hass,
hass_client,
config_entry,
setup_platform,
create_device,
):
"""Test configuration error."""
create_device.create(raw_data=DEVICE_API_DATA)
await setup_platform()
assert config_entry.state is ConfigEntryState.LOADED
device_registry = dr.async_get(hass)
device = device_registry.async_get_device({(DOMAIN, NEST_DEVICE_ID)})
assert device is not None
with patch(
"homeassistant.components.nest.diagnostics._get_nest_devices",
side_effect=ApiException("Device manager failure"),
):
assert await get_diagnostics_for_config_entry(
hass, hass_client, config_entry
) == {"error": "Device manager failure"}
assert await get_diagnostics_for_device(
hass, hass_client, config_entry, device
) == {"error": "Device manager failure"}
@pytest.mark.parametrize("nest_test_config", [TEST_CONFIG_LEGACY]) @pytest.mark.parametrize("nest_test_config", [TEST_CONFIG_LEGACY])
async def test_legacy_config_entry_diagnostics( async def test_legacy_config_entry_diagnostics(
hass, hass_client, config_entry, setup_base_platform hass, hass_client, config_entry, setup_base_platform