Use HassKey in cloud integration (#120322)

pull/120376/head
epenet 2024-06-24 21:02:08 +02:00 committed by GitHub
parent b223cb7bb9
commit ea09d0cbed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 109 additions and 102 deletions

View File

@ -55,6 +55,7 @@ from .const import (
CONF_SERVICEHANDLERS_SERVER, CONF_SERVICEHANDLERS_SERVER,
CONF_THINGTALK_SERVER, CONF_THINGTALK_SERVER,
CONF_USER_POOL_ID, CONF_USER_POOL_ID,
DATA_CLOUD,
DATA_PLATFORMS_SETUP, DATA_PLATFORMS_SETUP,
DOMAIN, DOMAIN,
MODE_DEV, MODE_DEV,
@ -155,14 +156,14 @@ def async_is_logged_in(hass: HomeAssistant) -> bool:
Note: This returns True even if not currently connected to the cloud. Note: This returns True even if not currently connected to the cloud.
""" """
return DOMAIN in hass.data and hass.data[DOMAIN].is_logged_in return DATA_CLOUD in hass.data and hass.data[DATA_CLOUD].is_logged_in
@bind_hass @bind_hass
@callback @callback
def async_is_connected(hass: HomeAssistant) -> bool: def async_is_connected(hass: HomeAssistant) -> bool:
"""Test if connected to the cloud.""" """Test if connected to the cloud."""
return DOMAIN in hass.data and hass.data[DOMAIN].iot.connected return DATA_CLOUD in hass.data and hass.data[DATA_CLOUD].iot.connected
@callback @callback
@ -178,7 +179,7 @@ def async_listen_connection_change(
@callback @callback
def async_active_subscription(hass: HomeAssistant) -> bool: def async_active_subscription(hass: HomeAssistant) -> bool:
"""Test if user has an active subscription.""" """Test if user has an active subscription."""
return async_is_logged_in(hass) and not hass.data[DOMAIN].subscription_expired return async_is_logged_in(hass) and not hass.data[DATA_CLOUD].subscription_expired
async def async_get_or_create_cloudhook(hass: HomeAssistant, webhook_id: str) -> str: async def async_get_or_create_cloudhook(hass: HomeAssistant, webhook_id: str) -> str:
@ -189,7 +190,7 @@ async def async_get_or_create_cloudhook(hass: HomeAssistant, webhook_id: str) ->
if not async_is_logged_in(hass): if not async_is_logged_in(hass):
raise CloudNotAvailable raise CloudNotAvailable
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
cloudhooks = cloud.client.cloudhooks cloudhooks = cloud.client.cloudhooks
if hook := cloudhooks.get(webhook_id): if hook := cloudhooks.get(webhook_id):
return cast(str, hook["cloudhook_url"]) return cast(str, hook["cloudhook_url"])
@ -206,7 +207,7 @@ async def async_create_cloudhook(hass: HomeAssistant, webhook_id: str) -> str:
if not async_is_logged_in(hass): if not async_is_logged_in(hass):
raise CloudNotAvailable raise CloudNotAvailable
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
hook = await cloud.cloudhooks.async_create(webhook_id, True) hook = await cloud.cloudhooks.async_create(webhook_id, True)
cloudhook_url: str = hook["cloudhook_url"] cloudhook_url: str = hook["cloudhook_url"]
return cloudhook_url return cloudhook_url
@ -215,10 +216,10 @@ async def async_create_cloudhook(hass: HomeAssistant, webhook_id: str) -> str:
@bind_hass @bind_hass
async def async_delete_cloudhook(hass: HomeAssistant, webhook_id: str) -> None: async def async_delete_cloudhook(hass: HomeAssistant, webhook_id: str) -> None:
"""Delete a cloudhook.""" """Delete a cloudhook."""
if DOMAIN not in hass.data: if DATA_CLOUD not in hass.data:
raise CloudNotAvailable raise CloudNotAvailable
await hass.data[DOMAIN].cloudhooks.async_delete(webhook_id) await hass.data[DATA_CLOUD].cloudhooks.async_delete(webhook_id)
@bind_hass @bind_hass
@ -228,10 +229,10 @@ def async_remote_ui_url(hass: HomeAssistant) -> str:
if not async_is_logged_in(hass): if not async_is_logged_in(hass):
raise CloudNotAvailable raise CloudNotAvailable
if not hass.data[DOMAIN].client.prefs.remote_enabled: if not hass.data[DATA_CLOUD].client.prefs.remote_enabled:
raise CloudNotAvailable raise CloudNotAvailable
if not (remote_domain := hass.data[DOMAIN].client.prefs.remote_domain): if not (remote_domain := hass.data[DATA_CLOUD].client.prefs.remote_domain):
raise CloudNotAvailable raise CloudNotAvailable
return f"https://{remote_domain}" return f"https://{remote_domain}"
@ -256,7 +257,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
# Initialize Cloud # Initialize Cloud
websession = async_get_clientsession(hass) websession = async_get_clientsession(hass)
client = CloudClient(hass, prefs, websession, alexa_conf, google_conf) client = CloudClient(hass, prefs, websession, alexa_conf, google_conf)
cloud = hass.data[DOMAIN] = Cloud(client, **kwargs) cloud = hass.data[DATA_CLOUD] = Cloud(client, **kwargs)
async def _shutdown(event: Event) -> None: async def _shutdown(event: Event) -> None:
"""Shutdown event.""" """Shutdown event."""
@ -373,9 +374,7 @@ def _remote_handle_prefs_updated(cloud: Cloud[CloudClient]) -> None:
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up a config entry.""" """Set up a config entry."""
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
stt_tts_entities_added: asyncio.Event = hass.data[DATA_PLATFORMS_SETUP][ stt_tts_entities_added = hass.data[DATA_PLATFORMS_SETUP]["stt_tts_entities_added"]
"stt_tts_entities_added"
]
stt_tts_entities_added.set() stt_tts_entities_added.set()
return True return True

View File

@ -14,7 +14,7 @@ from homeassistant.const import __version__ as HA_VERSION
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_entry_oauth2_flow, event from homeassistant.helpers import config_entry_oauth2_flow, event
from .const import DOMAIN from .const import DATA_CLOUD, DOMAIN
DATA_SERVICES = "cloud_account_link_services" DATA_SERVICES = "cloud_account_link_services"
CACHE_TIMEOUT = 3600 CACHE_TIMEOUT = 3600
@ -68,7 +68,9 @@ async def _get_services(hass: HomeAssistant) -> list[dict[str, Any]]:
return services # noqa: RET504 return services # noqa: RET504
try: try:
services = await account_link.async_fetch_available_services(hass.data[DOMAIN]) services = await account_link.async_fetch_available_services(
hass.data[DATA_CLOUD]
)
except (aiohttp.ClientError, TimeoutError): except (aiohttp.ClientError, TimeoutError):
return [] return []
@ -105,7 +107,7 @@ class CloudOAuth2Implementation(config_entry_oauth2_flow.AbstractOAuth2Implement
async def async_generate_authorize_url(self, flow_id: str) -> str: async def async_generate_authorize_url(self, flow_id: str) -> str:
"""Generate a url for the user to authorize.""" """Generate a url for the user to authorize."""
helper = account_link.AuthorizeAccountHelper( helper = account_link.AuthorizeAccountHelper(
self.hass.data[DOMAIN], self.service self.hass.data[DATA_CLOUD], self.service
) )
authorize_url = await helper.async_get_authorize_url() authorize_url = await helper.async_get_authorize_url()
@ -138,6 +140,6 @@ class CloudOAuth2Implementation(config_entry_oauth2_flow.AbstractOAuth2Implement
async def _async_refresh_token(self, token: dict) -> dict: async def _async_refresh_token(self, token: dict) -> dict:
"""Refresh a token.""" """Refresh a token."""
new_token = await account_link.async_fetch_access_token( new_token = await account_link.async_fetch_access_token(
self.hass.data[DOMAIN], self.service, token["refresh_token"] self.hass.data[DATA_CLOUD], self.service, token["refresh_token"]
) )
return {**token, **new_token} return {**token, **new_token}

View File

@ -27,7 +27,7 @@ async def async_create_cloud_pipeline(hass: HomeAssistant) -> str | None:
"""Create a cloud assist pipeline.""" """Create a cloud assist pipeline."""
# Wait for stt and tts platforms to set up and entities to be added # Wait for stt and tts platforms to set up and entities to be added
# before creating the pipeline. # before creating the pipeline.
platforms_setup: dict[str, asyncio.Event] = hass.data[DATA_PLATFORMS_SETUP] platforms_setup = hass.data[DATA_PLATFORMS_SETUP]
await asyncio.gather(*(event.wait() for event in platforms_setup.values())) await asyncio.gather(*(event.wait() for event in platforms_setup.values()))
# Make sure the pipeline store is loaded, needed because assist_pipeline # Make sure the pipeline store is loaded, needed because assist_pipeline
# is an after dependency of cloud # is an after dependency of cloud
@ -91,7 +91,7 @@ async def async_migrate_cloud_pipeline_engine(
else: else:
raise ValueError(f"Invalid platform {platform}") raise ValueError(f"Invalid platform {platform}")
platforms_setup: dict[str, asyncio.Event] = hass.data[DATA_PLATFORMS_SETUP] platforms_setup = hass.data[DATA_PLATFORMS_SETUP]
await platforms_setup[wait_for_platform].wait() await platforms_setup[wait_for_platform].wait()
# Make sure the pipeline store is loaded, needed because assist_pipeline # Make sure the pipeline store is loaded, needed because assist_pipeline

View File

@ -18,7 +18,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .client import CloudClient from .client import CloudClient
from .const import DISPATCHER_REMOTE_UPDATE, DOMAIN from .const import DATA_CLOUD, DISPATCHER_REMOTE_UPDATE
WAIT_UNTIL_CHANGE = 3 WAIT_UNTIL_CHANGE = 3
@ -29,7 +29,7 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up the Home Assistant Cloud binary sensors.""" """Set up the Home Assistant Cloud binary sensors."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
async_add_entities([CloudRemoteBinary(cloud)]) async_add_entities([CloudRemoteBinary(cloud)])

View File

@ -2,12 +2,22 @@
from __future__ import annotations from __future__ import annotations
from typing import Any import asyncio
from typing import TYPE_CHECKING, Any
from homeassistant.util.hass_dict import HassKey
from homeassistant.util.signal_type import SignalType from homeassistant.util.signal_type import SignalType
if TYPE_CHECKING:
from hass_nabucasa import Cloud
from .client import CloudClient
DOMAIN = "cloud" DOMAIN = "cloud"
DATA_PLATFORMS_SETUP = "cloud_platforms_setup" DATA_CLOUD: HassKey[Cloud[CloudClient]] = HassKey(DOMAIN)
DATA_PLATFORMS_SETUP: HassKey[dict[str, asyncio.Event]] = HassKey(
"cloud_platforms_setup"
)
REQUEST_TIMEOUT = 10 REQUEST_TIMEOUT = 10
PREF_ENABLE_ALEXA = "alexa_enabled" PREF_ENABLE_ALEXA = "alexa_enabled"

View File

@ -38,7 +38,7 @@ from .alexa_config import entity_supported as entity_supported_by_alexa
from .assist_pipeline import async_create_cloud_pipeline from .assist_pipeline import async_create_cloud_pipeline
from .client import CloudClient from .client import CloudClient
from .const import ( from .const import (
DOMAIN, DATA_CLOUD,
PREF_ALEXA_REPORT_STATE, PREF_ALEXA_REPORT_STATE,
PREF_DISABLE_2FA, PREF_DISABLE_2FA,
PREF_ENABLE_ALEXA, PREF_ENABLE_ALEXA,
@ -196,7 +196,7 @@ class GoogleActionsSyncView(HomeAssistantView):
async def post(self, request: web.Request) -> web.Response: async def post(self, request: web.Request) -> web.Response:
"""Trigger a Google Actions sync.""" """Trigger a Google Actions sync."""
hass = request.app[KEY_HASS] hass = request.app[KEY_HASS]
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
gconf = await cloud.client.get_google_config() gconf = await cloud.client.get_google_config()
status = await gconf.async_sync_entities(gconf.agent_user_id) status = await gconf.async_sync_entities(gconf.agent_user_id)
return self.json({}, status_code=status) return self.json({}, status_code=status)
@ -216,7 +216,7 @@ class CloudLoginView(HomeAssistantView):
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response: async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
"""Handle login request.""" """Handle login request."""
hass = request.app[KEY_HASS] hass = request.app[KEY_HASS]
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
await cloud.login(data["email"], data["password"]) await cloud.login(data["email"], data["password"])
if "assist_pipeline" in hass.config.components: if "assist_pipeline" in hass.config.components:
@ -237,7 +237,7 @@ class CloudLogoutView(HomeAssistantView):
async def post(self, request: web.Request) -> web.Response: async def post(self, request: web.Request) -> web.Response:
"""Handle logout request.""" """Handle logout request."""
hass = request.app[KEY_HASS] hass = request.app[KEY_HASS]
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
async with asyncio.timeout(REQUEST_TIMEOUT): async with asyncio.timeout(REQUEST_TIMEOUT):
await cloud.logout() await cloud.logout()
@ -264,7 +264,7 @@ class CloudRegisterView(HomeAssistantView):
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response: async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
"""Handle registration request.""" """Handle registration request."""
hass = request.app[KEY_HASS] hass = request.app[KEY_HASS]
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
client_metadata = None client_metadata = None
@ -301,7 +301,7 @@ class CloudResendConfirmView(HomeAssistantView):
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response: async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
"""Handle resending confirm email code request.""" """Handle resending confirm email code request."""
hass = request.app[KEY_HASS] hass = request.app[KEY_HASS]
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
async with asyncio.timeout(REQUEST_TIMEOUT): async with asyncio.timeout(REQUEST_TIMEOUT):
await cloud.auth.async_resend_email_confirm(data["email"]) await cloud.auth.async_resend_email_confirm(data["email"])
@ -321,7 +321,7 @@ class CloudForgotPasswordView(HomeAssistantView):
async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response: async def post(self, request: web.Request, data: dict[str, Any]) -> web.Response:
"""Handle forgot password request.""" """Handle forgot password request."""
hass = request.app[KEY_HASS] hass = request.app[KEY_HASS]
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
async with asyncio.timeout(REQUEST_TIMEOUT): async with asyncio.timeout(REQUEST_TIMEOUT):
await cloud.auth.async_forgot_password(data["email"]) await cloud.auth.async_forgot_password(data["email"])
@ -341,7 +341,7 @@ async def websocket_cloud_remove_data(
Async friendly. Async friendly.
""" """
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
if cloud.is_logged_in: if cloud.is_logged_in:
connection.send_message( connection.send_message(
websocket_api.error_message( websocket_api.error_message(
@ -367,7 +367,7 @@ async def websocket_cloud_status(
Async friendly. Async friendly.
""" """
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
connection.send_message( connection.send_message(
websocket_api.result_message(msg["id"], await _account_data(hass, cloud)) websocket_api.result_message(msg["id"], await _account_data(hass, cloud))
) )
@ -391,7 +391,7 @@ def _require_cloud_login(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Require to be logged into the cloud.""" """Require to be logged into the cloud."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
if not cloud.is_logged_in: if not cloud.is_logged_in:
connection.send_message( connection.send_message(
websocket_api.error_message( websocket_api.error_message(
@ -414,7 +414,7 @@ async def websocket_subscription(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Handle request for account info.""" """Handle request for account info."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
if (data := await async_subscription_info(cloud)) is None: if (data := await async_subscription_info(cloud)) is None:
connection.send_error( connection.send_error(
msg["id"], "request_failed", "Failed to request subscription" msg["id"], "request_failed", "Failed to request subscription"
@ -457,7 +457,7 @@ async def websocket_update_prefs(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Handle request for account info.""" """Handle request for account info."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
changes = dict(msg) changes = dict(msg)
changes.pop("id") changes.pop("id")
@ -508,7 +508,7 @@ async def websocket_hook_create(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Handle request for account info.""" """Handle request for account info."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
hook = await cloud.cloudhooks.async_create(msg["webhook_id"], False) hook = await cloud.cloudhooks.async_create(msg["webhook_id"], False)
connection.send_message(websocket_api.result_message(msg["id"], hook)) connection.send_message(websocket_api.result_message(msg["id"], hook))
@ -528,7 +528,7 @@ async def websocket_hook_delete(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Handle request for account info.""" """Handle request for account info."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
await cloud.cloudhooks.async_delete(msg["webhook_id"]) await cloud.cloudhooks.async_delete(msg["webhook_id"])
connection.send_message(websocket_api.result_message(msg["id"])) connection.send_message(websocket_api.result_message(msg["id"]))
@ -597,7 +597,7 @@ async def websocket_remote_connect(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Handle request for connect remote.""" """Handle request for connect remote."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
await cloud.client.prefs.async_update(remote_enabled=True) await cloud.client.prefs.async_update(remote_enabled=True)
connection.send_result(msg["id"], await _account_data(hass, cloud)) connection.send_result(msg["id"], await _account_data(hass, cloud))
@ -613,7 +613,7 @@ async def websocket_remote_disconnect(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Handle request for disconnect remote.""" """Handle request for disconnect remote."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
await cloud.client.prefs.async_update(remote_enabled=False) await cloud.client.prefs.async_update(remote_enabled=False)
connection.send_result(msg["id"], await _account_data(hass, cloud)) connection.send_result(msg["id"], await _account_data(hass, cloud))
@ -634,7 +634,7 @@ async def google_assistant_get(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Get data for a single google assistant entity.""" """Get data for a single google assistant entity."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
gconf = await cloud.client.get_google_config() gconf = await cloud.client.get_google_config()
entity_id: str = msg["entity_id"] entity_id: str = msg["entity_id"]
state = hass.states.get(entity_id) state = hass.states.get(entity_id)
@ -682,7 +682,7 @@ async def google_assistant_list(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""List all google assistant entities.""" """List all google assistant entities."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
gconf = await cloud.client.get_google_config() gconf = await cloud.client.get_google_config()
entities = google_helpers.async_get_entities(hass, gconf) entities = google_helpers.async_get_entities(hass, gconf)
@ -774,7 +774,7 @@ async def alexa_list(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""List all alexa entities.""" """List all alexa entities."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
alexa_config = await cloud.client.get_alexa_config() alexa_config = await cloud.client.get_alexa_config()
entities = alexa_entities.async_get_entities(hass, alexa_config) entities = alexa_entities.async_get_entities(hass, alexa_config)
@ -800,7 +800,7 @@ async def alexa_sync(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Sync with Alexa.""" """Sync with Alexa."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
alexa_config = await cloud.client.get_alexa_config() alexa_config = await cloud.client.get_alexa_config()
async with asyncio.timeout(10): async with asyncio.timeout(10):
@ -830,7 +830,7 @@ async def thingtalk_convert(
msg: dict[str, Any], msg: dict[str, Any],
) -> None: ) -> None:
"""Convert a query.""" """Convert a query."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
async with asyncio.timeout(10): async with asyncio.timeout(10):
try: try:

View File

@ -5,7 +5,6 @@ from __future__ import annotations
import asyncio import asyncio
from typing import Any from typing import Any
from hass_nabucasa import Cloud
import voluptuous as vol import voluptuous as vol
from homeassistant.components.repairs import ( from homeassistant.components.repairs import (
@ -17,8 +16,7 @@ from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers import issue_registry as ir from homeassistant.helpers import issue_registry as ir
from .client import CloudClient from .const import DATA_CLOUD, DOMAIN
from .const import DOMAIN
from .subscription import async_migrate_paypal_agreement, async_subscription_info from .subscription import async_migrate_paypal_agreement, async_subscription_info
BACKOFF_TIME = 5 BACKOFF_TIME = 5
@ -73,7 +71,7 @@ class LegacySubscriptionRepairFlow(RepairsFlow):
async def async_step_change_plan(self, _: None = None) -> FlowResult: async def async_step_change_plan(self, _: None = None) -> FlowResult:
"""Wait for the user to authorize the app installation.""" """Wait for the user to authorize the app installation."""
cloud: Cloud[CloudClient] = self.hass.data[DOMAIN] cloud = self.hass.data[DATA_CLOUD]
async def _async_wait_for_plan_change() -> None: async def _async_wait_for_plan_change() -> None:
flow_manager = repairs_flow_manager(self.hass) flow_manager = repairs_flow_manager(self.hass)

View File

@ -2,7 +2,6 @@
from __future__ import annotations from __future__ import annotations
import asyncio
from collections.abc import AsyncIterable from collections.abc import AsyncIterable
import logging import logging
@ -28,7 +27,7 @@ from homeassistant.setup import async_when_setup
from .assist_pipeline import async_migrate_cloud_pipeline_engine from .assist_pipeline import async_migrate_cloud_pipeline_engine
from .client import CloudClient from .client import CloudClient
from .const import DATA_PLATFORMS_SETUP, DOMAIN, STT_ENTITY_UNIQUE_ID from .const import DATA_CLOUD, DATA_PLATFORMS_SETUP, STT_ENTITY_UNIQUE_ID
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -39,9 +38,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up Home Assistant Cloud speech platform via config entry.""" """Set up Home Assistant Cloud speech platform via config entry."""
stt_platform_loaded: asyncio.Event = hass.data[DATA_PLATFORMS_SETUP][Platform.STT] stt_platform_loaded = hass.data[DATA_PLATFORMS_SETUP][Platform.STT]
stt_platform_loaded.set() stt_platform_loaded.set()
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
async_add_entities([CloudProviderEntity(cloud)]) async_add_entities([CloudProviderEntity(cloud)])

View File

@ -2,13 +2,10 @@
from typing import Any from typing import Any
from hass_nabucasa import Cloud
from homeassistant.components import system_health from homeassistant.components import system_health
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from .client import CloudClient from .const import DATA_CLOUD
from .const import DOMAIN
@callback @callback
@ -21,7 +18,7 @@ def async_register(
async def system_health_info(hass: HomeAssistant) -> dict[str, Any]: async def system_health_info(hass: HomeAssistant) -> dict[str, Any]:
"""Get info for the info page.""" """Get info for the info page."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
client = cloud.client client = cloud.client
data: dict[str, Any] = { data: dict[str, Any] = {

View File

@ -2,7 +2,6 @@
from __future__ import annotations from __future__ import annotations
import asyncio
import logging import logging
from typing import Any from typing import Any
@ -31,7 +30,7 @@ from homeassistant.setup import async_when_setup
from .assist_pipeline import async_migrate_cloud_pipeline_engine from .assist_pipeline import async_migrate_cloud_pipeline_engine
from .client import CloudClient from .client import CloudClient
from .const import DATA_PLATFORMS_SETUP, DOMAIN, TTS_ENTITY_UNIQUE_ID from .const import DATA_CLOUD, DATA_PLATFORMS_SETUP, DOMAIN, TTS_ENTITY_UNIQUE_ID
from .prefs import CloudPreferences from .prefs import CloudPreferences
ATTR_GENDER = "gender" ATTR_GENDER = "gender"
@ -97,7 +96,7 @@ async def async_get_engine(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> CloudProvider: ) -> CloudProvider:
"""Set up Cloud speech component.""" """Set up Cloud speech component."""
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
cloud_provider = CloudProvider(cloud) cloud_provider = CloudProvider(cloud)
if discovery_info is not None: if discovery_info is not None:
discovery_info["platform_loaded"].set() discovery_info["platform_loaded"].set()
@ -110,9 +109,9 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback, async_add_entities: AddEntitiesCallback,
) -> None: ) -> None:
"""Set up Home Assistant Cloud text-to-speech platform.""" """Set up Home Assistant Cloud text-to-speech platform."""
tts_platform_loaded: asyncio.Event = hass.data[DATA_PLATFORMS_SETUP][Platform.TTS] tts_platform_loaded = hass.data[DATA_PLATFORMS_SETUP][Platform.TTS]
tts_platform_loaded.set() tts_platform_loaded.set()
cloud: Cloud[CloudClient] = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
async_add_entities([CloudTTSEntity(cloud)]) async_add_entities([CloudTTSEntity(cloud)])

View File

@ -2,10 +2,9 @@
from unittest.mock import AsyncMock, patch from unittest.mock import AsyncMock, patch
from hass_nabucasa import Cloud
from homeassistant.components import cloud from homeassistant.components import cloud
from homeassistant.components.cloud import const, prefs as cloud_prefs from homeassistant.components.cloud import const, prefs as cloud_prefs
from homeassistant.components.cloud.const import DATA_CLOUD
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
PIPELINE_DATA = { PIPELINE_DATA = {
@ -64,7 +63,7 @@ async def mock_cloud(hass, config=None):
assert await async_setup_component(hass, "homeassistant", {}) assert await async_setup_component(hass, "homeassistant", {})
assert await async_setup_component(hass, cloud.DOMAIN, {"cloud": config or {}}) assert await async_setup_component(hass, cloud.DOMAIN, {"cloud": config or {}})
cloud_inst: Cloud = hass.data["cloud"] cloud_inst = hass.data[DATA_CLOUD]
with patch("hass_nabucasa.Cloud.run_executor", AsyncMock(return_value=None)): with patch("hass_nabucasa.Cloud.run_executor", AsyncMock(return_value=None)):
await cloud_inst.initialize() await cloud_inst.initialize()
@ -79,5 +78,5 @@ def mock_cloud_prefs(hass, prefs):
const.PREF_GOOGLE_SETTINGS_VERSION: cloud_prefs.GOOGLE_SETTINGS_VERSION, const.PREF_GOOGLE_SETTINGS_VERSION: cloud_prefs.GOOGLE_SETTINGS_VERSION,
} }
prefs_to_set.update(prefs) prefs_to_set.update(prefs)
hass.data[cloud.DOMAIN].client._prefs._prefs = prefs_to_set hass.data[DATA_CLOUD].client._prefs._prefs = prefs_to_set
return hass.data[cloud.DOMAIN].client._prefs return hass.data[DATA_CLOUD].client._prefs

View File

@ -17,7 +17,8 @@ import jwt
import pytest import pytest
from typing_extensions import AsyncGenerator from typing_extensions import AsyncGenerator
from homeassistant.components.cloud import CloudClient, const, prefs from homeassistant.components.cloud import CloudClient, prefs
from homeassistant.components.cloud.const import DATA_CLOUD
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
@ -223,7 +224,7 @@ async def mock_cloud_setup(hass):
@pytest.fixture @pytest.fixture
def mock_cloud_login(hass, mock_cloud_setup): def mock_cloud_login(hass, mock_cloud_setup):
"""Mock cloud is logged in.""" """Mock cloud is logged in."""
hass.data[const.DOMAIN].id_token = jwt.encode( hass.data[DATA_CLOUD].id_token = jwt.encode(
{ {
"email": "hello@home-assistant.io", "email": "hello@home-assistant.io",
"custom:sub-exp": "2300-01-03", "custom:sub-exp": "2300-01-03",
@ -231,7 +232,7 @@ def mock_cloud_login(hass, mock_cloud_setup):
}, },
"test", "test",
) )
with patch.object(hass.data[const.DOMAIN].auth, "async_check_token"): with patch.object(hass.data[DATA_CLOUD].auth, "async_check_token"):
yield yield
@ -248,7 +249,7 @@ def mock_auth_fixture():
@pytest.fixture @pytest.fixture
def mock_expired_cloud_login(hass, mock_cloud_setup): def mock_expired_cloud_login(hass, mock_cloud_setup):
"""Mock cloud is logged in.""" """Mock cloud is logged in."""
hass.data[const.DOMAIN].id_token = jwt.encode( hass.data[DATA_CLOUD].id_token = jwt.encode(
{ {
"email": "hello@home-assistant.io", "email": "hello@home-assistant.io",
"custom:sub-exp": "2018-01-01", "custom:sub-exp": "2018-01-01",

View File

@ -9,6 +9,7 @@ import pytest
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components.cloud import account_link from homeassistant.components.cloud import account_link
from homeassistant.components.cloud.const import DATA_CLOUD
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType from homeassistant.data_entry_flow import FlowResultType
from homeassistant.helpers import config_entry_oauth2_flow from homeassistant.helpers import config_entry_oauth2_flow
@ -133,7 +134,7 @@ async def test_setup_provide_implementation(hass: HomeAssistant) -> None:
async def test_get_services_cached(hass: HomeAssistant) -> None: async def test_get_services_cached(hass: HomeAssistant) -> None:
"""Test that we cache services.""" """Test that we cache services."""
hass.data["cloud"] = None hass.data[DATA_CLOUD] = None
services = 1 services = 1
@ -165,7 +166,7 @@ async def test_get_services_cached(hass: HomeAssistant) -> None:
async def test_get_services_error(hass: HomeAssistant) -> None: async def test_get_services_error(hass: HomeAssistant) -> None:
"""Test that we cache services.""" """Test that we cache services."""
hass.data["cloud"] = None hass.data[DATA_CLOUD] = None
with ( with (
patch.object(account_link, "CACHE_TIMEOUT", 0), patch.object(account_link, "CACHE_TIMEOUT", 0),
@ -181,7 +182,7 @@ async def test_get_services_error(hass: HomeAssistant) -> None:
@pytest.mark.usefixtures("current_request_with_host") @pytest.mark.usefixtures("current_request_with_host")
async def test_implementation(hass: HomeAssistant, flow_handler) -> None: async def test_implementation(hass: HomeAssistant, flow_handler) -> None:
"""Test Cloud OAuth2 implementation.""" """Test Cloud OAuth2 implementation."""
hass.data["cloud"] = None hass.data[DATA_CLOUD] = None
impl = account_link.CloudOAuth2Implementation(hass, "test") impl = account_link.CloudOAuth2Implementation(hass, "test")
assert impl.name == "Home Assistant Cloud" assert impl.name == "Home Assistant Cloud"

View File

@ -8,6 +8,7 @@ import pytest
from homeassistant.components.alexa import errors from homeassistant.components.alexa import errors
from homeassistant.components.cloud import ALEXA_SCHEMA, alexa_config from homeassistant.components.cloud import ALEXA_SCHEMA, alexa_config
from homeassistant.components.cloud.const import ( from homeassistant.components.cloud.const import (
DATA_CLOUD,
PREF_ALEXA_DEFAULT_EXPOSE, PREF_ALEXA_DEFAULT_EXPOSE,
PREF_ALEXA_ENTITY_CONFIGS, PREF_ALEXA_ENTITY_CONFIGS,
PREF_SHOULD_EXPOSE, PREF_SHOULD_EXPOSE,
@ -425,7 +426,7 @@ async def test_alexa_entity_registry_sync(
expose_new(hass, True) expose_new(hass, True)
await alexa_config.CloudAlexaConfig( await alexa_config.CloudAlexaConfig(
hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
).async_initialize() ).async_initialize()
with patch_sync_helper() as (to_update, to_remove): with patch_sync_helper() as (to_update, to_remove):
@ -506,11 +507,11 @@ def test_enabled_requires_valid_sub(
) -> None: ) -> None:
"""Test that alexa config enabled requires a valid Cloud sub.""" """Test that alexa config enabled requires a valid Cloud sub."""
assert cloud_prefs.alexa_enabled assert cloud_prefs.alexa_enabled
assert hass.data["cloud"].is_logged_in assert hass.data[DATA_CLOUD].is_logged_in
assert hass.data["cloud"].subscription_expired assert hass.data[DATA_CLOUD].subscription_expired
config = alexa_config.CloudAlexaConfig( config = alexa_config.CloudAlexaConfig(
hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
) )
assert not config.enabled assert not config.enabled

View File

@ -15,6 +15,7 @@ from homeassistant.components.cloud.client import (
CloudClient, CloudClient,
) )
from homeassistant.components.cloud.const import ( from homeassistant.components.cloud.const import (
DATA_CLOUD,
PREF_ALEXA_REPORT_STATE, PREF_ALEXA_REPORT_STATE,
PREF_ENABLE_ALEXA, PREF_ENABLE_ALEXA,
PREF_ENABLE_GOOGLE, PREF_ENABLE_GOOGLE,
@ -63,7 +64,7 @@ async def test_handler_alexa(hass: HomeAssistant) -> None:
) )
mock_cloud_prefs(hass, {PREF_ALEXA_REPORT_STATE: False}) mock_cloud_prefs(hass, {PREF_ALEXA_REPORT_STATE: False})
cloud = hass.data["cloud"] cloud = hass.data[DATA_CLOUD]
resp = await cloud.client.async_alexa_message( resp = await cloud.client.async_alexa_message(
test_alexa.get_new_request("Alexa.Discovery", "Discover") test_alexa.get_new_request("Alexa.Discovery", "Discover")
@ -83,7 +84,7 @@ async def test_handler_alexa(hass: HomeAssistant) -> None:
async def test_handler_alexa_disabled(hass: HomeAssistant, mock_cloud_fixture) -> None: async def test_handler_alexa_disabled(hass: HomeAssistant, mock_cloud_fixture) -> None:
"""Test handler Alexa when user has disabled it.""" """Test handler Alexa when user has disabled it."""
mock_cloud_fixture._prefs[PREF_ENABLE_ALEXA] = False mock_cloud_fixture._prefs[PREF_ENABLE_ALEXA] = False
cloud = hass.data["cloud"] cloud = hass.data[DATA_CLOUD]
resp = await cloud.client.async_alexa_message( resp = await cloud.client.async_alexa_message(
test_alexa.get_new_request("Alexa.Discovery", "Discover") test_alexa.get_new_request("Alexa.Discovery", "Discover")
@ -117,7 +118,7 @@ async def test_handler_google_actions(hass: HomeAssistant) -> None:
) )
mock_cloud_prefs(hass, {}) mock_cloud_prefs(hass, {})
cloud = hass.data["cloud"] cloud = hass.data[DATA_CLOUD]
reqid = "5711642932632160983" reqid = "5711642932632160983"
data = {"requestId": reqid, "inputs": [{"intent": "action.devices.SYNC"}]} data = {"requestId": reqid, "inputs": [{"intent": "action.devices.SYNC"}]}
@ -164,7 +165,7 @@ async def test_handler_google_actions_disabled(
reqid = "5711642932632160983" reqid = "5711642932632160983"
data = {"requestId": reqid, "inputs": [{"intent": intent}]} data = {"requestId": reqid, "inputs": [{"intent": intent}]}
cloud = hass.data["cloud"] cloud = hass.data[DATA_CLOUD]
with patch( with patch(
"hass_nabucasa.Cloud._decode_claims", "hass_nabucasa.Cloud._decode_claims",
return_value={"cognito:username": "myUserName"}, return_value={"cognito:username": "myUserName"},
@ -182,7 +183,7 @@ async def test_webhook_msg(
with patch("hass_nabucasa.Cloud.initialize"): with patch("hass_nabucasa.Cloud.initialize"):
setup = await async_setup_component(hass, "cloud", {"cloud": {}}) setup = await async_setup_component(hass, "cloud", {"cloud": {}})
assert setup assert setup
cloud = hass.data["cloud"] cloud = hass.data[DATA_CLOUD]
await cloud.client.prefs.async_initialize() await cloud.client.prefs.async_initialize()
await cloud.client.prefs.async_update( await cloud.client.prefs.async_update(
@ -269,7 +270,7 @@ async def test_google_config_expose_entity(
"light", "test", "unique", suggested_object_id="kitchen" "light", "test", "unique", suggested_object_id="kitchen"
) )
cloud_client = hass.data[DOMAIN].client cloud_client = hass.data[DATA_CLOUD].client
state = State(entity_entry.entity_id, "on") state = State(entity_entry.entity_id, "on")
gconf = await cloud_client.get_google_config() gconf = await cloud_client.get_google_config()
@ -293,7 +294,7 @@ async def test_google_config_should_2fa(
"light", "test", "unique", suggested_object_id="kitchen" "light", "test", "unique", suggested_object_id="kitchen"
) )
cloud_client = hass.data[DOMAIN].client cloud_client = hass.data[DATA_CLOUD].client
gconf = await cloud_client.get_google_config() gconf = await cloud_client.get_google_config()
state = State(entity_entry.entity_id, "on") state = State(entity_entry.entity_id, "on")
@ -350,7 +351,7 @@ async def test_system_msg(hass: HomeAssistant) -> None:
with patch("hass_nabucasa.Cloud.initialize"): with patch("hass_nabucasa.Cloud.initialize"):
setup = await async_setup_component(hass, "cloud", {"cloud": {}}) setup = await async_setup_component(hass, "cloud", {"cloud": {}})
assert setup assert setup
cloud = hass.data["cloud"] cloud = hass.data[DATA_CLOUD]
assert cloud.client.relayer_region is None assert cloud.client.relayer_region is None
@ -373,7 +374,7 @@ async def test_cloud_connection_info(hass: HomeAssistant) -> None:
hexmock.return_value = "12345678901234567890" hexmock.return_value = "12345678901234567890"
setup = await async_setup_component(hass, "cloud", {"cloud": {}}) setup = await async_setup_component(hass, "cloud", {"cloud": {}})
assert setup assert setup
cloud = hass.data["cloud"] cloud = hass.data[DATA_CLOUD]
response = await cloud.client.async_cloud_connection_info({}) response = await cloud.client.async_cloud_connection_info({})

View File

@ -8,6 +8,7 @@ import pytest
from homeassistant.components.cloud import GACTIONS_SCHEMA from homeassistant.components.cloud import GACTIONS_SCHEMA
from homeassistant.components.cloud.const import ( from homeassistant.components.cloud.const import (
DATA_CLOUD,
PREF_DISABLE_2FA, PREF_DISABLE_2FA,
PREF_GOOGLE_DEFAULT_EXPOSE, PREF_GOOGLE_DEFAULT_EXPOSE,
PREF_GOOGLE_ENTITY_CONFIGS, PREF_GOOGLE_ENTITY_CONFIGS,
@ -196,7 +197,7 @@ async def test_google_entity_registry_sync(
expose_new(hass, True) expose_new(hass, True)
config = CloudGoogleConfig( config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
) )
await config.async_initialize() await config.async_initialize()
await config.async_connect_agent_user("mock-user-id") await config.async_connect_agent_user("mock-user-id")
@ -264,7 +265,7 @@ async def test_google_device_registry_sync(
) -> None: ) -> None:
"""Test Google config responds to device registry.""" """Test Google config responds to device registry."""
config = CloudGoogleConfig( config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
) )
# Enable exposing new entities to Google # Enable exposing new entities to Google
@ -333,7 +334,7 @@ async def test_sync_google_when_started(
) -> None: ) -> None:
"""Test Google config syncs on init.""" """Test Google config syncs on init."""
config = CloudGoogleConfig( config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
) )
with patch.object(config, "async_sync_entities_all") as mock_sync: with patch.object(config, "async_sync_entities_all") as mock_sync:
await config.async_initialize() await config.async_initialize()
@ -346,7 +347,7 @@ async def test_sync_google_on_home_assistant_start(
) -> None: ) -> None:
"""Test Google config syncs when home assistant started.""" """Test Google config syncs when home assistant started."""
config = CloudGoogleConfig( config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
) )
hass.set_state(CoreState.not_running) hass.set_state(CoreState.not_running)
with patch.object(config, "async_sync_entities_all") as mock_sync: with patch.object(config, "async_sync_entities_all") as mock_sync:
@ -441,11 +442,11 @@ def test_enabled_requires_valid_sub(
) -> None: ) -> None:
"""Test that google config enabled requires a valid Cloud sub.""" """Test that google config enabled requires a valid Cloud sub."""
assert cloud_prefs.google_enabled assert cloud_prefs.google_enabled
assert hass.data["cloud"].is_logged_in assert hass.data[DATA_CLOUD].is_logged_in
assert hass.data["cloud"].subscription_expired assert hass.data[DATA_CLOUD].subscription_expired
config = CloudGoogleConfig( config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
) )
assert not config.enabled assert not config.enabled
@ -494,7 +495,7 @@ async def test_google_handle_logout(
await cloud_prefs.get_cloud_user() await cloud_prefs.get_cloud_user()
with patch.object( with patch.object(
hass.data["cloud"].auth, hass.data[DATA_CLOUD].auth,
"async_check_token", "async_check_token",
side_effect=AssertionError("Should not be called"), side_effect=AssertionError("Should not be called"),
): ):
@ -857,7 +858,7 @@ async def test_google_config_get_agent_user_id(
) -> None: ) -> None:
"""Test overridden get_agent_user_id_from_webhook method.""" """Test overridden get_agent_user_id_from_webhook method."""
config = CloudGoogleConfig( config = CloudGoogleConfig(
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data[DATA_CLOUD]
) )
assert ( assert (
config.get_agent_user_id_from_webhook(cloud_prefs.google_local_webhook_id) config.get_agent_user_id_from_webhook(cloud_prefs.google_local_webhook_id)

View File

@ -4,7 +4,6 @@ from collections.abc import Callable, Coroutine
from typing import Any from typing import Any
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from hass_nabucasa import Cloud
import pytest import pytest
from homeassistant.components import cloud from homeassistant.components import cloud
@ -13,7 +12,7 @@ from homeassistant.components.cloud import (
CloudNotConnected, CloudNotConnected,
async_get_or_create_cloudhook, async_get_or_create_cloudhook,
) )
from homeassistant.components.cloud.const import DOMAIN, PREF_CLOUDHOOKS from homeassistant.components.cloud.const import DATA_CLOUD, DOMAIN, PREF_CLOUDHOOKS
from homeassistant.components.cloud.prefs import STORAGE_KEY from homeassistant.components.cloud.prefs import STORAGE_KEY
from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import Context, HomeAssistant from homeassistant.core import Context, HomeAssistant
@ -47,7 +46,7 @@ async def test_constructor_loads_info_from_config(hass: HomeAssistant) -> None:
) )
assert result assert result
cl = hass.data["cloud"] cl = hass.data[DATA_CLOUD]
assert cl.mode == cloud.MODE_DEV assert cl.mode == cloud.MODE_DEV
assert cl.cognito_client_id == "test-cognito_client_id" assert cl.cognito_client_id == "test-cognito_client_id"
assert cl.user_pool_id == "test-user_pool_id" assert cl.user_pool_id == "test-user_pool_id"
@ -65,7 +64,7 @@ async def test_remote_services(
hass: HomeAssistant, mock_cloud_fixture, hass_read_only_user: MockUser hass: HomeAssistant, mock_cloud_fixture, hass_read_only_user: MockUser
) -> None: ) -> None:
"""Setup cloud component and test services.""" """Setup cloud component and test services."""
cloud = hass.data[DOMAIN] cloud = hass.data[DATA_CLOUD]
assert hass.services.has_service(DOMAIN, "remote_connect") assert hass.services.has_service(DOMAIN, "remote_connect")
assert hass.services.has_service(DOMAIN, "remote_disconnect") assert hass.services.has_service(DOMAIN, "remote_disconnect")
@ -145,7 +144,7 @@ async def test_setup_existing_cloud_user(
async def test_on_connect(hass: HomeAssistant, mock_cloud_fixture) -> None: async def test_on_connect(hass: HomeAssistant, mock_cloud_fixture) -> None:
"""Test cloud on connect triggers.""" """Test cloud on connect triggers."""
cl: Cloud[cloud.client.CloudClient] = hass.data["cloud"] cl = hass.data[DATA_CLOUD]
assert len(cl.iot._on_connect) == 3 assert len(cl.iot._on_connect) == 3
@ -202,7 +201,7 @@ async def test_on_connect(hass: HomeAssistant, mock_cloud_fixture) -> None:
async def test_remote_ui_url(hass: HomeAssistant, mock_cloud_fixture) -> None: async def test_remote_ui_url(hass: HomeAssistant, mock_cloud_fixture) -> None:
"""Test getting remote ui url.""" """Test getting remote ui url."""
cl = hass.data["cloud"] cl = hass.data[DATA_CLOUD]
# Not logged in # Not logged in
with pytest.raises(cloud.CloudNotAvailable): with pytest.raises(cloud.CloudNotAvailable):