Import cloud (#64116)

* Add type hints to cloud

* Import cloud

* Adjust smartthings tests

Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
epenet
2022-01-14 16:35:35 +01:00
committed by GitHub
parent 9f61aecd5e
commit 2c0033254b
12 changed files with 46 additions and 52 deletions

View File

@@ -116,20 +116,20 @@ class CloudNotAvailable(HomeAssistantError):
@bind_hass @bind_hass
@callback @callback
def async_is_logged_in(hass) -> bool: def async_is_logged_in(hass: HomeAssistant) -> bool:
"""Test if user is logged in.""" """Test if user is logged in."""
return DOMAIN in hass.data and hass.data[DOMAIN].is_logged_in return DOMAIN in hass.data and hass.data[DOMAIN].is_logged_in
@bind_hass @bind_hass
@callback @callback
def async_active_subscription(hass) -> 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[DOMAIN].subscription_expired
@bind_hass @bind_hass
async def async_create_cloudhook(hass, webhook_id: str) -> str: async def async_create_cloudhook(hass: HomeAssistant, webhook_id: str) -> str:
"""Create a cloudhook.""" """Create a cloudhook."""
if not async_is_logged_in(hass): if not async_is_logged_in(hass):
raise CloudNotAvailable raise CloudNotAvailable
@@ -139,7 +139,7 @@ async def async_create_cloudhook(hass, webhook_id: str) -> str:
@bind_hass @bind_hass
async def async_delete_cloudhook(hass, 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 DOMAIN not in hass.data:
raise CloudNotAvailable raise CloudNotAvailable
@@ -149,7 +149,7 @@ async def async_delete_cloudhook(hass, webhook_id: str) -> None:
@bind_hass @bind_hass
@callback @callback
def async_remote_ui_url(hass) -> str: def async_remote_ui_url(hass: HomeAssistant) -> str:
"""Get the remote UI URL.""" """Get the remote UI URL."""
if not async_is_logged_in(hass): if not async_is_logged_in(hass):
raise CloudNotAvailable raise CloudNotAvailable

View File

@@ -10,6 +10,7 @@ import emoji
from nacl.secret import SecretBox from nacl.secret import SecretBox
import voluptuous as vol import voluptuous as vol
from homeassistant.components import cloud
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
from homeassistant.components.http.data_validator import RequestDataValidator from homeassistant.components.http.data_validator import RequestDataValidator
from homeassistant.const import ATTR_DEVICE_ID, CONF_WEBHOOK_ID from homeassistant.const import ATTR_DEVICE_ID, CONF_WEBHOOK_ID
@@ -68,10 +69,10 @@ class RegistrationsView(HomeAssistantView):
webhook_id = secrets.token_hex() webhook_id = secrets.token_hex()
if hass.components.cloud.async_active_subscription(): if cloud.async_active_subscription(hass):
data[ data[CONF_CLOUDHOOK_URL] = await cloud.async_create_cloudhook(
CONF_CLOUDHOOK_URL hass, webhook_id
] = await hass.components.cloud.async_create_cloudhook(webhook_id) )
data[CONF_WEBHOOK_ID] = webhook_id data[CONF_WEBHOOK_ID] = webhook_id
@@ -102,7 +103,7 @@ class RegistrationsView(HomeAssistantView):
remote_ui_url = None remote_ui_url = None
with suppress(hass.components.cloud.CloudNotAvailable): with suppress(hass.components.cloud.CloudNotAvailable):
remote_ui_url = hass.components.cloud.async_remote_ui_url() remote_ui_url = cloud.async_remote_ui_url(hass)
return self.json( return self.json(
{ {

View File

@@ -10,7 +10,7 @@ from aiohttp.web import HTTPBadRequest, Request, Response, json_response
from nacl.secret import SecretBox from nacl.secret import SecretBox
import voluptuous as vol import voluptuous as vol
from homeassistant.components import notify as hass_notify, tag from homeassistant.components import cloud, notify as hass_notify, tag
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DEVICE_CLASSES as BINARY_SENSOR_CLASSES, DEVICE_CLASSES as BINARY_SENSOR_CLASSES,
) )
@@ -593,7 +593,7 @@ async def webhook_get_config(hass, config_entry, data):
resp[CONF_CLOUDHOOK_URL] = config_entry.data[CONF_CLOUDHOOK_URL] resp[CONF_CLOUDHOOK_URL] = config_entry.data[CONF_CLOUDHOOK_URL]
with suppress(hass.components.cloud.CloudNotAvailable): with suppress(hass.components.cloud.CloudNotAvailable):
resp[CONF_REMOTE_UI_URL] = hass.components.cloud.async_remote_ui_url() resp[CONF_REMOTE_UI_URL] = cloud.async_remote_ui_url(hass)
return webhook_response(resp, registration=config_entry.data) return webhook_response(resp, registration=config_entry.data)

View File

@@ -183,10 +183,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
data = {**entry.data, CONF_WEBHOOK_ID: secrets.token_hex()} data = {**entry.data, CONF_WEBHOOK_ID: secrets.token_hex()}
hass.config_entries.async_update_entry(entry, data=data) hass.config_entries.async_update_entry(entry, data=data)
if hass.components.cloud.async_active_subscription(): if cloud.async_active_subscription(hass):
if CONF_CLOUDHOOK_URL not in entry.data: if CONF_CLOUDHOOK_URL not in entry.data:
webhook_url = await hass.components.cloud.async_create_cloudhook( webhook_url = await cloud.async_create_cloudhook(
entry.data[CONF_WEBHOOK_ID] hass, entry.data[CONF_WEBHOOK_ID]
) )
data = {**entry.data, CONF_CLOUDHOOK_URL: webhook_url} data = {**entry.data, CONF_CLOUDHOOK_URL: webhook_url}
hass.config_entries.async_update_entry(entry, data=data) hass.config_entries.async_update_entry(entry, data=data)
@@ -276,10 +276,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Cleanup when entry is removed.""" """Cleanup when entry is removed."""
if ( if CONF_WEBHOOK_ID in entry.data and cloud.async_active_subscription(hass):
CONF_WEBHOOK_ID in entry.data
and hass.components.cloud.async_active_subscription()
):
try: try:
_LOGGER.debug( _LOGGER.debug(
"Removing Netatmo cloudhook (%s)", entry.data[CONF_WEBHOOK_ID] "Removing Netatmo cloudhook (%s)", entry.data[CONF_WEBHOOK_ID]

View File

@@ -8,7 +8,7 @@ from aiohttp.web import json_response
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import mqtt, webhook from homeassistant.components import cloud, mqtt, webhook
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_GPS_ACCURACY, ATTR_GPS_ACCURACY,
@@ -126,7 +126,7 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
if not entry.data.get("cloudhook"): if not entry.data.get("cloudhook"):
return return
await hass.components.cloud.async_delete_cloudhook(entry.data[CONF_WEBHOOK_ID]) await cloud.async_delete_cloudhook(hass, entry.data[CONF_WEBHOOK_ID])
async def async_connect_mqtt(hass, component): async def async_connect_mqtt(hass, component):

View File

@@ -2,7 +2,7 @@
import secrets import secrets
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import webhook from homeassistant.components import cloud, webhook
from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.const import CONF_WEBHOOK_ID
from .const import DOMAIN from .const import DOMAIN
@@ -68,10 +68,8 @@ class OwnTracksFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def _get_webhook_id(self): async def _get_webhook_id(self):
"""Generate webhook ID.""" """Generate webhook ID."""
webhook_id = webhook.async_generate_id() webhook_id = webhook.async_generate_id()
if self.hass.components.cloud.async_active_subscription(): if cloud.async_active_subscription(self.hass):
webhook_url = await self.hass.components.cloud.async_create_cloudhook( webhook_url = await cloud.async_create_cloudhook(self.hass, webhook_id)
webhook_id
)
cloudhook = True cloudhook = True
else: else:
webhook_url = webhook.async_generate_url(self.hass, webhook_id) webhook_url = webhook.async_generate_url(self.hass, webhook_id)

View File

@@ -3,7 +3,7 @@ from pyplaato.plaato import PlaatoDeviceType
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import webhook from homeassistant.components import cloud, webhook
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_WEBHOOK_ID from homeassistant.const import CONF_SCAN_INTERVAL, CONF_TOKEN, CONF_WEBHOOK_ID
from homeassistant.core import callback from homeassistant.core import callback
@@ -141,10 +141,8 @@ class PlaatoConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
async def _get_webhook_id(self): async def _get_webhook_id(self):
"""Generate webhook ID.""" """Generate webhook ID."""
webhook_id = webhook.async_generate_id() webhook_id = webhook.async_generate_id()
if self.hass.components.cloud.async_active_subscription(): if cloud.async_active_subscription(self.hass):
webhook_url = await self.hass.components.cloud.async_create_cloudhook( webhook_url = await cloud.async_create_cloudhook(self.hass, webhook_id)
webhook_id
)
cloudhook = True cloudhook = True
else: else:
webhook_url = webhook.async_generate_url(self.hass, webhook_id) webhook_url = webhook.async_generate_url(self.hass, webhook_id)

View File

@@ -5,6 +5,7 @@ import secrets
from rachiopy import Rachio from rachiopy import Rachio
from requests.exceptions import ConnectTimeout from requests.exceptions import ConnectTimeout
from homeassistant.components import cloud
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, Platform from homeassistant.const import CONF_API_KEY, Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
@@ -36,7 +37,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Remove a rachio config entry.""" """Remove a rachio config entry."""
if CONF_CLOUDHOOK_URL in entry.data: if CONF_CLOUDHOOK_URL in entry.data:
await hass.components.cloud.async_delete_cloudhook(entry.data[CONF_WEBHOOK_ID]) await cloud.async_delete_cloudhook(hass, entry.data[CONF_WEBHOOK_ID])
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:

View File

@@ -1,7 +1,7 @@
"""Webhooks used by rachio.""" """Webhooks used by rachio."""
from aiohttp import web from aiohttp import web
from homeassistant.components import webhook from homeassistant.components import cloud, webhook
from homeassistant.const import URL_API from homeassistant.const import URL_API
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
@@ -115,11 +115,9 @@ async def async_get_or_create_registered_webhook_id_and_url(hass, entry):
config[CONF_WEBHOOK_ID] = webhook_id config[CONF_WEBHOOK_ID] = webhook_id
updated_config = True updated_config = True
if hass.components.cloud.async_active_subscription(): if cloud.async_active_subscription(hass):
if not (cloudhook_url := config.get(CONF_CLOUDHOOK_URL)): if not (cloudhook_url := config.get(CONF_CLOUDHOOK_URL)):
cloudhook_url = await hass.components.cloud.async_create_cloudhook( cloudhook_url = await cloud.async_create_cloudhook(hass, webhook_id)
webhook_id
)
config[CONF_CLOUDHOOK_URL] = cloudhook_url config[CONF_CLOUDHOOK_URL] = cloudhook_url
updated_config = True updated_config = True
webhook_url = cloudhook_url webhook_url = cloudhook_url

View File

@@ -23,7 +23,7 @@ from pysmartthings import (
SubscriptionEntity, SubscriptionEntity,
) )
from homeassistant.components import webhook from homeassistant.components import cloud, webhook
from homeassistant.const import CONF_WEBHOOK_ID from homeassistant.const import CONF_WEBHOOK_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.aiohttp_client import async_get_clientsession
@@ -94,7 +94,7 @@ async def validate_installed_app(api, installed_app_id: str):
def validate_webhook_requirements(hass: HomeAssistant) -> bool: def validate_webhook_requirements(hass: HomeAssistant) -> bool:
"""Ensure Home Assistant is setup properly to receive webhooks.""" """Ensure Home Assistant is setup properly to receive webhooks."""
if hass.components.cloud.async_active_subscription(): if cloud.async_active_subscription(hass):
return True return True
if hass.data[DOMAIN][CONF_CLOUDHOOK_URL] is not None: if hass.data[DOMAIN][CONF_CLOUDHOOK_URL] is not None:
return True return True
@@ -108,7 +108,7 @@ def get_webhook_url(hass: HomeAssistant) -> str:
Return the cloudhook if available, otherwise local webhook. Return the cloudhook if available, otherwise local webhook.
""" """
cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL] cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL]
if hass.components.cloud.async_active_subscription() and cloudhook_url is not None: if cloud.async_active_subscription(hass) and cloudhook_url is not None:
return cloudhook_url return cloudhook_url
return webhook.async_generate_url(hass, hass.data[DOMAIN][CONF_WEBHOOK_ID]) return webhook.async_generate_url(hass, hass.data[DOMAIN][CONF_WEBHOOK_ID])
@@ -229,11 +229,11 @@ async def setup_smartapp_endpoint(hass: HomeAssistant):
cloudhook_url = config.get(CONF_CLOUDHOOK_URL) cloudhook_url = config.get(CONF_CLOUDHOOK_URL)
if ( if (
cloudhook_url is None cloudhook_url is None
and hass.components.cloud.async_active_subscription() and cloud.async_active_subscription(hass)
and not hass.config_entries.async_entries(DOMAIN) and not hass.config_entries.async_entries(DOMAIN)
): ):
cloudhook_url = await hass.components.cloud.async_create_cloudhook( cloudhook_url = await cloud.async_create_cloudhook(
config[CONF_WEBHOOK_ID] hass, config[CONF_WEBHOOK_ID]
) )
config[CONF_CLOUDHOOK_URL] = cloudhook_url config[CONF_CLOUDHOOK_URL] = cloudhook_url
await store.async_save(config) await store.async_save(config)
@@ -279,10 +279,8 @@ async def unload_smartapp_endpoint(hass: HomeAssistant):
return return
# Remove the cloudhook if it was created # Remove the cloudhook if it was created
cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL] cloudhook_url = hass.data[DOMAIN][CONF_CLOUDHOOK_URL]
if cloudhook_url and hass.components.cloud.async_is_logged_in(): if cloudhook_url and cloud.async_is_logged_in(hass):
await hass.components.cloud.async_delete_cloudhook( await cloud.async_delete_cloudhook(hass, hass.data[DOMAIN][CONF_WEBHOOK_ID])
hass.data[DOMAIN][CONF_WEBHOOK_ID]
)
# Remove cloudhook from storage # Remove cloudhook from storage
store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY)
await store.async_save( await store.async_save(

View File

@@ -6,6 +6,7 @@ import secrets
from toonapi import Status, Toon, ToonError from toonapi import Status, Toon, ToonError
from homeassistant.components import cloud
from homeassistant.components.webhook import ( from homeassistant.components.webhook import (
async_register as webhook_register, async_register as webhook_register,
async_unregister as webhook_unregister, async_unregister as webhook_unregister,
@@ -57,11 +58,11 @@ class ToonDataUpdateCoordinator(DataUpdateCoordinator[Status]):
data = {**self.entry.data, CONF_WEBHOOK_ID: secrets.token_hex()} data = {**self.entry.data, CONF_WEBHOOK_ID: secrets.token_hex()}
self.hass.config_entries.async_update_entry(self.entry, data=data) self.hass.config_entries.async_update_entry(self.entry, data=data)
if self.hass.components.cloud.async_active_subscription(): if cloud.async_active_subscription(self.hass):
if CONF_CLOUDHOOK_URL not in self.entry.data: if CONF_CLOUDHOOK_URL not in self.entry.data:
webhook_url = await self.hass.components.cloud.async_create_cloudhook( webhook_url = await cloud.async_create_cloudhook(
self.entry.data[CONF_WEBHOOK_ID] self.hass, self.entry.data[CONF_WEBHOOK_ID]
) )
data = {**self.entry.data, CONF_CLOUDHOOK_URL: webhook_url} data = {**self.entry.data, CONF_CLOUDHOOK_URL: webhook_url}
self.hass.config_entries.async_update_entry(self.entry, data=data) self.hass.config_entries.async_update_entry(self.entry, data=data)

View File

@@ -355,9 +355,11 @@ async def test_entry_created_with_cloudhook(
request.refresh_token = refresh_token request.refresh_token = refresh_token
with patch.object( with patch.object(
hass.components.cloud, "async_active_subscription", Mock(return_value=True) smartapp.cloud,
"async_active_subscription",
Mock(return_value=True),
), patch.object( ), patch.object(
hass.components.cloud, smartapp.cloud,
"async_create_cloudhook", "async_create_cloudhook",
AsyncMock(return_value="http://cloud.test"), AsyncMock(return_value="http://cloud.test"),
) as mock_create_cloudhook: ) as mock_create_cloudhook: