Allow exposing domains in cloud (#39216)

This commit is contained in:
Paulus Schoutsen 2020-08-28 16:49:17 +02:00 committed by GitHub
parent 414a59ae9f
commit 5217139e0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 193 additions and 43 deletions

View file

@ -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

View file

@ -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"

View file

@ -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:

View file

@ -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):

View file

@ -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,
} }

View file

@ -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."""

View file

@ -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)

View file

@ -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