Allow exposing domains in cloud (#39216)
This commit is contained in:
parent
414a59ae9f
commit
5217139e0b
8 changed files with 193 additions and 43 deletions
|
@ -14,18 +14,13 @@ from homeassistant.components.alexa import (
|
||||||
state_report as alexa_state_report,
|
state_report as alexa_state_report,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_BAD_REQUEST
|
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_BAD_REQUEST
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback, split_entity_id
|
||||||
from homeassistant.helpers import entity_registry
|
from homeassistant.helpers import entity_registry
|
||||||
from homeassistant.helpers.event import async_call_later
|
from homeassistant.helpers.event import async_call_later
|
||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
from .const import (
|
from .const import CONF_ENTITY_CONFIG, CONF_FILTER, PREF_SHOULD_EXPOSE, RequireRelink
|
||||||
CONF_ENTITY_CONFIG,
|
from .prefs import CloudPreferences
|
||||||
CONF_FILTER,
|
|
||||||
DEFAULT_SHOULD_EXPOSE,
|
|
||||||
PREF_SHOULD_EXPOSE,
|
|
||||||
RequireRelink,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -37,7 +32,7 @@ SYNC_DELAY = 1
|
||||||
class AlexaConfig(alexa_config.AbstractConfig):
|
class AlexaConfig(alexa_config.AbstractConfig):
|
||||||
"""Alexa Configuration."""
|
"""Alexa Configuration."""
|
||||||
|
|
||||||
def __init__(self, hass, config, prefs, cloud):
|
def __init__(self, hass, config, prefs: CloudPreferences, cloud):
|
||||||
"""Initialize the Alexa config."""
|
"""Initialize the Alexa config."""
|
||||||
super().__init__(hass)
|
super().__init__(hass)
|
||||||
self._config = config
|
self._config = config
|
||||||
|
@ -46,6 +41,7 @@ class AlexaConfig(alexa_config.AbstractConfig):
|
||||||
self._token = None
|
self._token = None
|
||||||
self._token_valid = None
|
self._token_valid = None
|
||||||
self._cur_entity_prefs = prefs.alexa_entity_configs
|
self._cur_entity_prefs = prefs.alexa_entity_configs
|
||||||
|
self._cur_default_expose = prefs.alexa_default_expose
|
||||||
self._alexa_sync_unsub = None
|
self._alexa_sync_unsub = None
|
||||||
self._endpoint = None
|
self._endpoint = None
|
||||||
|
|
||||||
|
@ -99,7 +95,17 @@ class AlexaConfig(alexa_config.AbstractConfig):
|
||||||
|
|
||||||
entity_configs = self._prefs.alexa_entity_configs
|
entity_configs = self._prefs.alexa_entity_configs
|
||||||
entity_config = entity_configs.get(entity_id, {})
|
entity_config = entity_configs.get(entity_id, {})
|
||||||
return entity_config.get(PREF_SHOULD_EXPOSE, DEFAULT_SHOULD_EXPOSE)
|
entity_expose = entity_config.get(PREF_SHOULD_EXPOSE)
|
||||||
|
if entity_expose is not None:
|
||||||
|
return entity_expose
|
||||||
|
|
||||||
|
default_expose = self._prefs.alexa_default_expose
|
||||||
|
|
||||||
|
# Backwards compat
|
||||||
|
if default_expose is None:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return split_entity_id(entity_id)[0] in default_expose
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_invalidate_access_token(self):
|
def async_invalidate_access_token(self):
|
||||||
|
@ -147,16 +153,24 @@ class AlexaConfig(alexa_config.AbstractConfig):
|
||||||
await self.async_sync_entities()
|
await self.async_sync_entities()
|
||||||
return
|
return
|
||||||
|
|
||||||
# If entity prefs are the same or we have filter in config.yaml,
|
# If user has filter in config.yaml, don't sync.
|
||||||
# don't sync.
|
if not self._config[CONF_FILTER].empty_filter:
|
||||||
|
return
|
||||||
|
|
||||||
|
# If entity prefs are the same, don't sync.
|
||||||
if (
|
if (
|
||||||
self._cur_entity_prefs is prefs.alexa_entity_configs
|
self._cur_entity_prefs is prefs.alexa_entity_configs
|
||||||
or not self._config[CONF_FILTER].empty_filter
|
and self._cur_default_expose is prefs.alexa_default_expose
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._alexa_sync_unsub:
|
if self._alexa_sync_unsub:
|
||||||
self._alexa_sync_unsub()
|
self._alexa_sync_unsub()
|
||||||
|
self._alexa_sync_unsub = None
|
||||||
|
|
||||||
|
if self._cur_default_expose is not prefs.alexa_default_expose:
|
||||||
|
await self.async_sync_entities()
|
||||||
|
return
|
||||||
|
|
||||||
self._alexa_sync_unsub = async_call_later(
|
self._alexa_sync_unsub = async_call_later(
|
||||||
self.hass, SYNC_DELAY, self._sync_prefs
|
self.hass, SYNC_DELAY, self._sync_prefs
|
||||||
|
|
|
@ -18,10 +18,25 @@ PREF_ALIASES = "aliases"
|
||||||
PREF_SHOULD_EXPOSE = "should_expose"
|
PREF_SHOULD_EXPOSE = "should_expose"
|
||||||
PREF_GOOGLE_LOCAL_WEBHOOK_ID = "google_local_webhook_id"
|
PREF_GOOGLE_LOCAL_WEBHOOK_ID = "google_local_webhook_id"
|
||||||
PREF_USERNAME = "username"
|
PREF_USERNAME = "username"
|
||||||
DEFAULT_SHOULD_EXPOSE = True
|
PREF_ALEXA_DEFAULT_EXPOSE = "alexa_default_expose"
|
||||||
|
PREF_GOOGLE_DEFAULT_EXPOSE = "google_default_expose"
|
||||||
DEFAULT_DISABLE_2FA = False
|
DEFAULT_DISABLE_2FA = False
|
||||||
DEFAULT_ALEXA_REPORT_STATE = False
|
DEFAULT_ALEXA_REPORT_STATE = False
|
||||||
DEFAULT_GOOGLE_REPORT_STATE = False
|
DEFAULT_GOOGLE_REPORT_STATE = False
|
||||||
|
DEFAULT_EXPOSED_DOMAINS = [
|
||||||
|
"climate",
|
||||||
|
"cover",
|
||||||
|
"fan",
|
||||||
|
"humidifier",
|
||||||
|
"light",
|
||||||
|
"lock",
|
||||||
|
"scene",
|
||||||
|
"script",
|
||||||
|
"sensor",
|
||||||
|
"switch",
|
||||||
|
"vacuum",
|
||||||
|
"water_heater",
|
||||||
|
]
|
||||||
|
|
||||||
CONF_ALEXA = "alexa"
|
CONF_ALEXA = "alexa"
|
||||||
CONF_ALIASES = "aliases"
|
CONF_ALIASES = "aliases"
|
||||||
|
|
|
@ -11,16 +11,16 @@ from homeassistant.const import (
|
||||||
EVENT_HOMEASSISTANT_STARTED,
|
EVENT_HOMEASSISTANT_STARTED,
|
||||||
HTTP_OK,
|
HTTP_OK,
|
||||||
)
|
)
|
||||||
from homeassistant.core import CoreState, callback
|
from homeassistant.core import CoreState, callback, split_entity_id
|
||||||
from homeassistant.helpers import entity_registry
|
from homeassistant.helpers import entity_registry
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
CONF_ENTITY_CONFIG,
|
CONF_ENTITY_CONFIG,
|
||||||
DEFAULT_DISABLE_2FA,
|
DEFAULT_DISABLE_2FA,
|
||||||
DEFAULT_SHOULD_EXPOSE,
|
|
||||||
PREF_DISABLE_2FA,
|
PREF_DISABLE_2FA,
|
||||||
PREF_SHOULD_EXPOSE,
|
PREF_SHOULD_EXPOSE,
|
||||||
)
|
)
|
||||||
|
from .prefs import CloudPreferences
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
class CloudGoogleConfig(AbstractConfig):
|
class CloudGoogleConfig(AbstractConfig):
|
||||||
"""HA Cloud Configuration for Google Assistant."""
|
"""HA Cloud Configuration for Google Assistant."""
|
||||||
|
|
||||||
def __init__(self, hass, config, cloud_user, prefs, cloud):
|
def __init__(self, hass, config, cloud_user, prefs: CloudPreferences, cloud):
|
||||||
"""Initialize the Google config."""
|
"""Initialize the Google config."""
|
||||||
super().__init__(hass)
|
super().__init__(hass)
|
||||||
self._config = config
|
self._config = config
|
||||||
|
@ -36,6 +36,7 @@ class CloudGoogleConfig(AbstractConfig):
|
||||||
self._prefs = prefs
|
self._prefs = prefs
|
||||||
self._cloud = cloud
|
self._cloud = cloud
|
||||||
self._cur_entity_prefs = self._prefs.google_entity_configs
|
self._cur_entity_prefs = self._prefs.google_entity_configs
|
||||||
|
self._cur_default_expose = self._prefs.google_default_expose
|
||||||
self._sync_entities_lock = asyncio.Lock()
|
self._sync_entities_lock = asyncio.Lock()
|
||||||
self._sync_on_started = False
|
self._sync_on_started = False
|
||||||
|
|
||||||
|
@ -104,7 +105,17 @@ class CloudGoogleConfig(AbstractConfig):
|
||||||
|
|
||||||
entity_configs = self._prefs.google_entity_configs
|
entity_configs = self._prefs.google_entity_configs
|
||||||
entity_config = entity_configs.get(entity_id, {})
|
entity_config = entity_configs.get(entity_id, {})
|
||||||
return entity_config.get(PREF_SHOULD_EXPOSE, DEFAULT_SHOULD_EXPOSE)
|
entity_expose = entity_config.get(PREF_SHOULD_EXPOSE)
|
||||||
|
if entity_expose is not None:
|
||||||
|
return entity_expose
|
||||||
|
|
||||||
|
default_expose = self._prefs.google_default_expose
|
||||||
|
|
||||||
|
# Backwards compat
|
||||||
|
if default_expose is None:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return split_entity_id(entity_id)[0] in default_expose
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def agent_user_id(self):
|
def agent_user_id(self):
|
||||||
|
@ -153,8 +164,8 @@ class CloudGoogleConfig(AbstractConfig):
|
||||||
# don't sync.
|
# don't sync.
|
||||||
elif (
|
elif (
|
||||||
self._cur_entity_prefs is not prefs.google_entity_configs
|
self._cur_entity_prefs is not prefs.google_entity_configs
|
||||||
and self._config["filter"].empty_filter
|
or self._cur_default_expose is not prefs.google_default_expose
|
||||||
):
|
) and self._config["filter"].empty_filter:
|
||||||
self.async_schedule_google_sync_all()
|
self.async_schedule_google_sync_all()
|
||||||
|
|
||||||
if self.enabled and not self.is_local_sdk_active:
|
if self.enabled and not self.is_local_sdk_active:
|
||||||
|
@ -162,6 +173,9 @@ class CloudGoogleConfig(AbstractConfig):
|
||||||
elif not self.enabled and self.is_local_sdk_active:
|
elif not self.enabled and self.is_local_sdk_active:
|
||||||
self.async_disable_local_sdk()
|
self.async_disable_local_sdk()
|
||||||
|
|
||||||
|
self._cur_entity_prefs = prefs.google_entity_configs
|
||||||
|
self._cur_default_expose = prefs.google_default_expose
|
||||||
|
|
||||||
async def _handle_entity_registry_updated(self, event):
|
async def _handle_entity_registry_updated(self, event):
|
||||||
"""Handle when entity registry updated."""
|
"""Handle when entity registry updated."""
|
||||||
if not self.enabled or not self._cloud.is_logged_in:
|
if not self.enabled or not self._cloud.is_logged_in:
|
||||||
|
|
|
@ -24,9 +24,11 @@ from homeassistant.core import callback
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
PREF_ALEXA_DEFAULT_EXPOSE,
|
||||||
PREF_ALEXA_REPORT_STATE,
|
PREF_ALEXA_REPORT_STATE,
|
||||||
PREF_ENABLE_ALEXA,
|
PREF_ENABLE_ALEXA,
|
||||||
PREF_ENABLE_GOOGLE,
|
PREF_ENABLE_GOOGLE,
|
||||||
|
PREF_GOOGLE_DEFAULT_EXPOSE,
|
||||||
PREF_GOOGLE_REPORT_STATE,
|
PREF_GOOGLE_REPORT_STATE,
|
||||||
PREF_GOOGLE_SECURE_DEVICES_PIN,
|
PREF_GOOGLE_SECURE_DEVICES_PIN,
|
||||||
REQUEST_TIMEOUT,
|
REQUEST_TIMEOUT,
|
||||||
|
@ -371,6 +373,8 @@ async def websocket_subscription(hass, connection, msg):
|
||||||
vol.Optional(PREF_ENABLE_ALEXA): bool,
|
vol.Optional(PREF_ENABLE_ALEXA): bool,
|
||||||
vol.Optional(PREF_ALEXA_REPORT_STATE): bool,
|
vol.Optional(PREF_ALEXA_REPORT_STATE): bool,
|
||||||
vol.Optional(PREF_GOOGLE_REPORT_STATE): bool,
|
vol.Optional(PREF_GOOGLE_REPORT_STATE): bool,
|
||||||
|
vol.Optional(PREF_ALEXA_DEFAULT_EXPOSE): [str],
|
||||||
|
vol.Optional(PREF_GOOGLE_DEFAULT_EXPOSE): [str],
|
||||||
vol.Optional(PREF_GOOGLE_SECURE_DEVICES_PIN): vol.Any(None, str),
|
vol.Optional(PREF_GOOGLE_SECURE_DEVICES_PIN): vol.Any(None, str),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -514,7 +518,7 @@ async def google_assistant_list(hass, connection, msg):
|
||||||
{
|
{
|
||||||
"type": "cloud/google_assistant/entities/update",
|
"type": "cloud/google_assistant/entities/update",
|
||||||
"entity_id": str,
|
"entity_id": str,
|
||||||
vol.Optional("should_expose"): bool,
|
vol.Optional("should_expose"): vol.Any(None, bool),
|
||||||
vol.Optional("override_name"): str,
|
vol.Optional("override_name"): str,
|
||||||
vol.Optional("aliases"): [str],
|
vol.Optional("aliases"): [str],
|
||||||
vol.Optional("disable_2fa"): bool,
|
vol.Optional("disable_2fa"): bool,
|
||||||
|
@ -566,7 +570,7 @@ async def alexa_list(hass, connection, msg):
|
||||||
{
|
{
|
||||||
"type": "cloud/alexa/entities/update",
|
"type": "cloud/alexa/entities/update",
|
||||||
"entity_id": str,
|
"entity_id": str,
|
||||||
vol.Optional("should_expose"): bool,
|
vol.Optional("should_expose"): vol.Any(None, bool),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
async def alexa_update(hass, connection, msg):
|
async def alexa_update(hass, connection, msg):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""Preference management for cloud."""
|
"""Preference management for cloud."""
|
||||||
from ipaddress import ip_address
|
from ipaddress import ip_address
|
||||||
from typing import Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from homeassistant.auth.const import GROUP_ID_ADMIN
|
from homeassistant.auth.const import GROUP_ID_ADMIN
|
||||||
from homeassistant.auth.models import User
|
from homeassistant.auth.models import User
|
||||||
|
@ -9,8 +9,10 @@ from homeassistant.util.logging import async_create_catching_coro
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DEFAULT_ALEXA_REPORT_STATE,
|
DEFAULT_ALEXA_REPORT_STATE,
|
||||||
|
DEFAULT_EXPOSED_DOMAINS,
|
||||||
DEFAULT_GOOGLE_REPORT_STATE,
|
DEFAULT_GOOGLE_REPORT_STATE,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
PREF_ALEXA_DEFAULT_EXPOSE,
|
||||||
PREF_ALEXA_ENTITY_CONFIGS,
|
PREF_ALEXA_ENTITY_CONFIGS,
|
||||||
PREF_ALEXA_REPORT_STATE,
|
PREF_ALEXA_REPORT_STATE,
|
||||||
PREF_ALIASES,
|
PREF_ALIASES,
|
||||||
|
@ -20,6 +22,7 @@ from .const import (
|
||||||
PREF_ENABLE_ALEXA,
|
PREF_ENABLE_ALEXA,
|
||||||
PREF_ENABLE_GOOGLE,
|
PREF_ENABLE_GOOGLE,
|
||||||
PREF_ENABLE_REMOTE,
|
PREF_ENABLE_REMOTE,
|
||||||
|
PREF_GOOGLE_DEFAULT_EXPOSE,
|
||||||
PREF_GOOGLE_ENTITY_CONFIGS,
|
PREF_GOOGLE_ENTITY_CONFIGS,
|
||||||
PREF_GOOGLE_LOCAL_WEBHOOK_ID,
|
PREF_GOOGLE_LOCAL_WEBHOOK_ID,
|
||||||
PREF_GOOGLE_REPORT_STATE,
|
PREF_GOOGLE_REPORT_STATE,
|
||||||
|
@ -81,6 +84,8 @@ class CloudPreferences:
|
||||||
alexa_entity_configs=_UNDEF,
|
alexa_entity_configs=_UNDEF,
|
||||||
alexa_report_state=_UNDEF,
|
alexa_report_state=_UNDEF,
|
||||||
google_report_state=_UNDEF,
|
google_report_state=_UNDEF,
|
||||||
|
alexa_default_expose=_UNDEF,
|
||||||
|
google_default_expose=_UNDEF,
|
||||||
):
|
):
|
||||||
"""Update user preferences."""
|
"""Update user preferences."""
|
||||||
prefs = {**self._prefs}
|
prefs = {**self._prefs}
|
||||||
|
@ -96,6 +101,8 @@ class CloudPreferences:
|
||||||
(PREF_ALEXA_ENTITY_CONFIGS, alexa_entity_configs),
|
(PREF_ALEXA_ENTITY_CONFIGS, alexa_entity_configs),
|
||||||
(PREF_ALEXA_REPORT_STATE, alexa_report_state),
|
(PREF_ALEXA_REPORT_STATE, alexa_report_state),
|
||||||
(PREF_GOOGLE_REPORT_STATE, google_report_state),
|
(PREF_GOOGLE_REPORT_STATE, google_report_state),
|
||||||
|
(PREF_ALEXA_DEFAULT_EXPOSE, alexa_default_expose),
|
||||||
|
(PREF_GOOGLE_DEFAULT_EXPOSE, google_default_expose),
|
||||||
):
|
):
|
||||||
if value is not _UNDEF:
|
if value is not _UNDEF:
|
||||||
prefs[key] = value
|
prefs[key] = value
|
||||||
|
@ -185,15 +192,17 @@ class CloudPreferences:
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
"""Return dictionary version."""
|
"""Return dictionary version."""
|
||||||
return {
|
return {
|
||||||
|
PREF_ALEXA_DEFAULT_EXPOSE: self.alexa_default_expose,
|
||||||
|
PREF_ALEXA_ENTITY_CONFIGS: self.alexa_entity_configs,
|
||||||
|
PREF_ALEXA_REPORT_STATE: self.alexa_report_state,
|
||||||
|
PREF_CLOUDHOOKS: self.cloudhooks,
|
||||||
PREF_ENABLE_ALEXA: self.alexa_enabled,
|
PREF_ENABLE_ALEXA: self.alexa_enabled,
|
||||||
PREF_ENABLE_GOOGLE: self.google_enabled,
|
PREF_ENABLE_GOOGLE: self.google_enabled,
|
||||||
PREF_ENABLE_REMOTE: self.remote_enabled,
|
PREF_ENABLE_REMOTE: self.remote_enabled,
|
||||||
PREF_GOOGLE_SECURE_DEVICES_PIN: self.google_secure_devices_pin,
|
PREF_GOOGLE_DEFAULT_EXPOSE: self.google_default_expose,
|
||||||
PREF_GOOGLE_ENTITY_CONFIGS: self.google_entity_configs,
|
PREF_GOOGLE_ENTITY_CONFIGS: self.google_entity_configs,
|
||||||
PREF_ALEXA_ENTITY_CONFIGS: self.alexa_entity_configs,
|
|
||||||
PREF_ALEXA_REPORT_STATE: self.alexa_report_state,
|
|
||||||
PREF_GOOGLE_REPORT_STATE: self.google_report_state,
|
PREF_GOOGLE_REPORT_STATE: self.google_report_state,
|
||||||
PREF_CLOUDHOOKS: self.cloudhooks,
|
PREF_GOOGLE_SECURE_DEVICES_PIN: self.google_secure_devices_pin,
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -219,6 +228,19 @@ class CloudPreferences:
|
||||||
"""Return if Alexa report state is enabled."""
|
"""Return if Alexa report state is enabled."""
|
||||||
return self._prefs.get(PREF_ALEXA_REPORT_STATE, DEFAULT_ALEXA_REPORT_STATE)
|
return self._prefs.get(PREF_ALEXA_REPORT_STATE, DEFAULT_ALEXA_REPORT_STATE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alexa_default_expose(self) -> Optional[List[str]]:
|
||||||
|
"""Return array of entity domains that are exposed by default to Alexa.
|
||||||
|
|
||||||
|
Can return None, in which case for backwards should be interpreted as allow all domains.
|
||||||
|
"""
|
||||||
|
return self._prefs.get(PREF_ALEXA_DEFAULT_EXPOSE)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alexa_entity_configs(self):
|
||||||
|
"""Return Alexa Entity configurations."""
|
||||||
|
return self._prefs.get(PREF_ALEXA_ENTITY_CONFIGS, {})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def google_enabled(self):
|
def google_enabled(self):
|
||||||
"""Return if Google is enabled."""
|
"""Return if Google is enabled."""
|
||||||
|
@ -245,9 +267,12 @@ class CloudPreferences:
|
||||||
return self._prefs[PREF_GOOGLE_LOCAL_WEBHOOK_ID]
|
return self._prefs[PREF_GOOGLE_LOCAL_WEBHOOK_ID]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def alexa_entity_configs(self):
|
def google_default_expose(self) -> Optional[List[str]]:
|
||||||
"""Return Alexa Entity configurations."""
|
"""Return array of entity domains that are exposed by default to Google.
|
||||||
return self._prefs.get(PREF_ALEXA_ENTITY_CONFIGS, {})
|
|
||||||
|
Can return None, in which case for backwards should be interpreted as allow all domains.
|
||||||
|
"""
|
||||||
|
return self._prefs.get(PREF_GOOGLE_DEFAULT_EXPOSE)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cloudhooks(self):
|
def cloudhooks(self):
|
||||||
|
@ -322,14 +347,16 @@ class CloudPreferences:
|
||||||
def _empty_config(self, username):
|
def _empty_config(self, username):
|
||||||
"""Return an empty config."""
|
"""Return an empty config."""
|
||||||
return {
|
return {
|
||||||
|
PREF_ALEXA_DEFAULT_EXPOSE: DEFAULT_EXPOSED_DOMAINS,
|
||||||
|
PREF_ALEXA_ENTITY_CONFIGS: {},
|
||||||
|
PREF_CLOUD_USER: None,
|
||||||
|
PREF_CLOUDHOOKS: {},
|
||||||
PREF_ENABLE_ALEXA: True,
|
PREF_ENABLE_ALEXA: True,
|
||||||
PREF_ENABLE_GOOGLE: True,
|
PREF_ENABLE_GOOGLE: True,
|
||||||
PREF_ENABLE_REMOTE: False,
|
PREF_ENABLE_REMOTE: False,
|
||||||
PREF_GOOGLE_SECURE_DEVICES_PIN: None,
|
PREF_GOOGLE_DEFAULT_EXPOSE: DEFAULT_EXPOSED_DOMAINS,
|
||||||
PREF_GOOGLE_ENTITY_CONFIGS: {},
|
PREF_GOOGLE_ENTITY_CONFIGS: {},
|
||||||
PREF_ALEXA_ENTITY_CONFIGS: {},
|
|
||||||
PREF_CLOUDHOOKS: {},
|
|
||||||
PREF_CLOUD_USER: None,
|
|
||||||
PREF_USERNAME: username,
|
|
||||||
PREF_GOOGLE_LOCAL_WEBHOOK_ID: self._hass.components.webhook.async_generate_id(),
|
PREF_GOOGLE_LOCAL_WEBHOOK_ID: self._hass.components.webhook.async_generate_id(),
|
||||||
|
PREF_GOOGLE_SECURE_DEVICES_PIN: None,
|
||||||
|
PREF_USERNAME: username,
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,22 @@ from tests.common import async_fire_time_changed
|
||||||
async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs):
|
async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs):
|
||||||
"""Test Alexa config should expose using prefs."""
|
"""Test Alexa config should expose using prefs."""
|
||||||
entity_conf = {"should_expose": False}
|
entity_conf = {"should_expose": False}
|
||||||
await cloud_prefs.async_update(alexa_entity_configs={"light.kitchen": entity_conf})
|
await cloud_prefs.async_update(
|
||||||
|
alexa_entity_configs={"light.kitchen": entity_conf},
|
||||||
|
alexa_default_expose=["light"],
|
||||||
|
)
|
||||||
conf = alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None)
|
conf = alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None)
|
||||||
|
|
||||||
assert not conf.should_expose("light.kitchen")
|
assert not conf.should_expose("light.kitchen")
|
||||||
entity_conf["should_expose"] = True
|
entity_conf["should_expose"] = True
|
||||||
assert conf.should_expose("light.kitchen")
|
assert conf.should_expose("light.kitchen")
|
||||||
|
|
||||||
|
entity_conf["should_expose"] = None
|
||||||
|
assert conf.should_expose("light.kitchen")
|
||||||
|
|
||||||
|
await cloud_prefs.async_update(alexa_default_expose=["sensor"],)
|
||||||
|
assert not conf.should_expose("light.kitchen")
|
||||||
|
|
||||||
|
|
||||||
async def test_alexa_config_report_state(hass, cloud_prefs):
|
async def test_alexa_config_report_state(hass, cloud_prefs):
|
||||||
"""Test Alexa config should expose using prefs."""
|
"""Test Alexa config should expose using prefs."""
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
"""Test the Cloud Google Config."""
|
"""Test the Cloud Google Config."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.cloud import GACTIONS_SCHEMA
|
from homeassistant.components.cloud import GACTIONS_SCHEMA
|
||||||
from homeassistant.components.cloud.google_config import CloudGoogleConfig
|
from homeassistant.components.cloud.google_config import CloudGoogleConfig
|
||||||
from homeassistant.components.google_assistant import helpers as ga_helpers
|
from homeassistant.components.google_assistant import helpers as ga_helpers
|
||||||
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, HTTP_NOT_FOUND
|
from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, HTTP_NOT_FOUND
|
||||||
from homeassistant.core import CoreState
|
from homeassistant.core import CoreState, State
|
||||||
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED
|
||||||
from homeassistant.util.dt import utcnow
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
|
@ -11,19 +13,24 @@ from tests.async_mock import AsyncMock, Mock, patch
|
||||||
from tests.common import async_fire_time_changed
|
from tests.common import async_fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
async def test_google_update_report_state(hass, cloud_prefs):
|
@pytest.fixture
|
||||||
"""Test Google config responds to updating preference."""
|
def mock_conf(hass, cloud_prefs):
|
||||||
config = CloudGoogleConfig(
|
"""Mock Google conf."""
|
||||||
|
return CloudGoogleConfig(
|
||||||
hass,
|
hass,
|
||||||
GACTIONS_SCHEMA({}),
|
GACTIONS_SCHEMA({}),
|
||||||
"mock-user-id",
|
"mock-user-id",
|
||||||
cloud_prefs,
|
cloud_prefs,
|
||||||
Mock(claims={"cognito:username": "abcdefghjkl"}),
|
Mock(claims={"cognito:username": "abcdefghjkl"}),
|
||||||
)
|
)
|
||||||
await config.async_initialize()
|
|
||||||
await config.async_connect_agent_user("mock-user-id")
|
|
||||||
|
|
||||||
with patch.object(config, "async_sync_entities") as mock_sync, patch(
|
|
||||||
|
async def test_google_update_report_state(mock_conf, hass, cloud_prefs):
|
||||||
|
"""Test Google config responds to updating preference."""
|
||||||
|
await mock_conf.async_initialize()
|
||||||
|
await mock_conf.async_connect_agent_user("mock-user-id")
|
||||||
|
|
||||||
|
with patch.object(mock_conf, "async_sync_entities") as mock_sync, patch(
|
||||||
"homeassistant.components.google_assistant.report_state.async_enable_report_state"
|
"homeassistant.components.google_assistant.report_state.async_enable_report_state"
|
||||||
) as mock_report_state:
|
) as mock_report_state:
|
||||||
await cloud_prefs.async_update(google_report_state=True)
|
await cloud_prefs.async_update(google_report_state=True)
|
||||||
|
@ -161,3 +168,24 @@ async def test_google_entity_registry_sync(hass, mock_cloud_login, cloud_prefs):
|
||||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(mock_sync.mock_calls) == 1
|
assert len(mock_sync.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_google_config_expose_entity_prefs(mock_conf, cloud_prefs):
|
||||||
|
"""Test Google config should expose using prefs."""
|
||||||
|
entity_conf = {"should_expose": False}
|
||||||
|
await cloud_prefs.async_update(
|
||||||
|
google_entity_configs={"light.kitchen": entity_conf},
|
||||||
|
google_default_expose=["light"],
|
||||||
|
)
|
||||||
|
|
||||||
|
state = State("light.kitchen", "on")
|
||||||
|
|
||||||
|
assert not mock_conf.should_expose(state)
|
||||||
|
entity_conf["should_expose"] = True
|
||||||
|
assert mock_conf.should_expose(state)
|
||||||
|
|
||||||
|
entity_conf["should_expose"] = None
|
||||||
|
assert mock_conf.should_expose(state)
|
||||||
|
|
||||||
|
await cloud_prefs.async_update(google_default_expose=["sensor"],)
|
||||||
|
assert not mock_conf.should_expose(state)
|
||||||
|
|
|
@ -355,6 +355,8 @@ async def test_websocket_status(
|
||||||
"google_enabled": True,
|
"google_enabled": True,
|
||||||
"google_entity_configs": {},
|
"google_entity_configs": {},
|
||||||
"google_secure_devices_pin": None,
|
"google_secure_devices_pin": None,
|
||||||
|
"google_default_expose": None,
|
||||||
|
"alexa_default_expose": None,
|
||||||
"alexa_entity_configs": {},
|
"alexa_entity_configs": {},
|
||||||
"alexa_report_state": False,
|
"alexa_report_state": False,
|
||||||
"google_report_state": False,
|
"google_report_state": False,
|
||||||
|
@ -487,6 +489,8 @@ async def test_websocket_update_preferences(
|
||||||
"alexa_enabled": False,
|
"alexa_enabled": False,
|
||||||
"google_enabled": False,
|
"google_enabled": False,
|
||||||
"google_secure_devices_pin": "1234",
|
"google_secure_devices_pin": "1234",
|
||||||
|
"google_default_expose": ["light", "switch"],
|
||||||
|
"alexa_default_expose": ["sensor", "media_player"],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
response = await client.receive_json()
|
response = await client.receive_json()
|
||||||
|
@ -495,6 +499,8 @@ async def test_websocket_update_preferences(
|
||||||
assert not setup_api.google_enabled
|
assert not setup_api.google_enabled
|
||||||
assert not setup_api.alexa_enabled
|
assert not setup_api.alexa_enabled
|
||||||
assert setup_api.google_secure_devices_pin == "1234"
|
assert setup_api.google_secure_devices_pin == "1234"
|
||||||
|
assert setup_api.google_default_expose == ["light", "switch"]
|
||||||
|
assert setup_api.alexa_default_expose == ["sensor", "media_player"]
|
||||||
|
|
||||||
|
|
||||||
async def test_websocket_update_preferences_require_relink(
|
async def test_websocket_update_preferences_require_relink(
|
||||||
|
@ -746,6 +752,25 @@ async def test_update_google_entity(hass, hass_ws_client, setup_api, mock_cloud_
|
||||||
"disable_2fa": False,
|
"disable_2fa": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await client.send_json(
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"type": "cloud/google_assistant/entities/update",
|
||||||
|
"entity_id": "light.kitchen",
|
||||||
|
"should_expose": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
response = await client.receive_json()
|
||||||
|
|
||||||
|
assert response["success"]
|
||||||
|
prefs = hass.data[DOMAIN].client.prefs
|
||||||
|
assert prefs.google_entity_configs["light.kitchen"] == {
|
||||||
|
"should_expose": None,
|
||||||
|
"override_name": "updated name",
|
||||||
|
"aliases": ["lefty", "righty"],
|
||||||
|
"disable_2fa": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_enabling_remote_trusted_proxies_local4(
|
async def test_enabling_remote_trusted_proxies_local4(
|
||||||
hass, hass_ws_client, setup_api, mock_cloud_login
|
hass, hass_ws_client, setup_api, mock_cloud_login
|
||||||
|
@ -834,6 +859,20 @@ async def test_update_alexa_entity(hass, hass_ws_client, setup_api, mock_cloud_l
|
||||||
prefs = hass.data[DOMAIN].client.prefs
|
prefs = hass.data[DOMAIN].client.prefs
|
||||||
assert prefs.alexa_entity_configs["light.kitchen"] == {"should_expose": False}
|
assert prefs.alexa_entity_configs["light.kitchen"] == {"should_expose": False}
|
||||||
|
|
||||||
|
await client.send_json(
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"type": "cloud/alexa/entities/update",
|
||||||
|
"entity_id": "light.kitchen",
|
||||||
|
"should_expose": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
response = await client.receive_json()
|
||||||
|
|
||||||
|
assert response["success"]
|
||||||
|
prefs = hass.data[DOMAIN].client.prefs
|
||||||
|
assert prefs.alexa_entity_configs["light.kitchen"] == {"should_expose": None}
|
||||||
|
|
||||||
|
|
||||||
async def test_sync_alexa_entities_timeout(
|
async def test_sync_alexa_entities_timeout(
|
||||||
hass, hass_ws_client, setup_api, mock_cloud_login
|
hass, hass_ws_client, setup_api, mock_cloud_login
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue