mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 14:17:45 +00:00
Avoid exposing unsupported entities to Google Assistant (#92105)
* Avoid exposing unsupported entities to Google Assistant * Add Google Assistant specific support sets * Add test
This commit is contained in:
parent
a164530a64
commit
65c9d4a4ae
@ -7,12 +7,14 @@ from typing import Any
|
|||||||
from hass_nabucasa import Cloud, cloud_api
|
from hass_nabucasa import Cloud, cloud_api
|
||||||
from hass_nabucasa.google_report_state import ErrorResponse
|
from hass_nabucasa.google_report_state import ErrorResponse
|
||||||
|
|
||||||
|
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||||
from homeassistant.components.google_assistant import DOMAIN as GOOGLE_DOMAIN
|
from homeassistant.components.google_assistant import DOMAIN as GOOGLE_DOMAIN
|
||||||
from homeassistant.components.google_assistant.helpers import AbstractConfig
|
from homeassistant.components.google_assistant.helpers import AbstractConfig
|
||||||
from homeassistant.components.homeassistant.exposed_entities import (
|
from homeassistant.components.homeassistant.exposed_entities import (
|
||||||
async_listen_entity_updates,
|
async_listen_entity_updates,
|
||||||
async_should_expose,
|
async_should_expose,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.sensor import SensorDeviceClass
|
||||||
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
|
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES
|
||||||
from homeassistant.core import (
|
from homeassistant.core import (
|
||||||
CoreState,
|
CoreState,
|
||||||
@ -22,6 +24,7 @@ from homeassistant.core import (
|
|||||||
split_entity_id,
|
split_entity_id,
|
||||||
)
|
)
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er, start
|
from homeassistant.helpers import device_registry as dr, entity_registry as er, start
|
||||||
|
from homeassistant.helpers.entity import get_device_class
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -39,6 +42,73 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
CLOUD_GOOGLE = f"{CLOUD_DOMAIN}.{GOOGLE_DOMAIN}"
|
CLOUD_GOOGLE = f"{CLOUD_DOMAIN}.{GOOGLE_DOMAIN}"
|
||||||
|
|
||||||
|
|
||||||
|
SUPPORTED_DOMAINS = {
|
||||||
|
"alarm_control_panel",
|
||||||
|
"button",
|
||||||
|
"camera",
|
||||||
|
"climate",
|
||||||
|
"cover",
|
||||||
|
"fan",
|
||||||
|
"group",
|
||||||
|
"humidifier",
|
||||||
|
"input_boolean",
|
||||||
|
"input_button",
|
||||||
|
"input_select",
|
||||||
|
"light",
|
||||||
|
"lock",
|
||||||
|
"media_player",
|
||||||
|
"scene",
|
||||||
|
"script",
|
||||||
|
"select",
|
||||||
|
"switch",
|
||||||
|
"vacuum",
|
||||||
|
}
|
||||||
|
|
||||||
|
SUPPORTED_BINARY_SENSOR_DEVICE_CLASSES = {
|
||||||
|
BinarySensorDeviceClass.DOOR,
|
||||||
|
BinarySensorDeviceClass.GARAGE_DOOR,
|
||||||
|
BinarySensorDeviceClass.LOCK,
|
||||||
|
BinarySensorDeviceClass.MOTION,
|
||||||
|
BinarySensorDeviceClass.OPENING,
|
||||||
|
BinarySensorDeviceClass.PRESENCE,
|
||||||
|
BinarySensorDeviceClass.WINDOW,
|
||||||
|
}
|
||||||
|
|
||||||
|
SUPPORTED_SENSOR_DEVICE_CLASSES = {
|
||||||
|
SensorDeviceClass.AQI,
|
||||||
|
SensorDeviceClass.CO,
|
||||||
|
SensorDeviceClass.CO2,
|
||||||
|
SensorDeviceClass.HUMIDITY,
|
||||||
|
SensorDeviceClass.PM10,
|
||||||
|
SensorDeviceClass.PM25,
|
||||||
|
SensorDeviceClass.TEMPERATURE,
|
||||||
|
SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _supported_legacy(hass: HomeAssistant, entity_id: str) -> bool:
|
||||||
|
"""Return if the entity is supported.
|
||||||
|
|
||||||
|
This is called when migrating from legacy config format to avoid exposing
|
||||||
|
all binary sensors and sensors.
|
||||||
|
"""
|
||||||
|
domain = split_entity_id(entity_id)[0]
|
||||||
|
if domain in SUPPORTED_DOMAINS:
|
||||||
|
return True
|
||||||
|
|
||||||
|
device_class = get_device_class(hass, entity_id)
|
||||||
|
if (
|
||||||
|
domain == "binary_sensor"
|
||||||
|
and device_class in SUPPORTED_BINARY_SENSOR_DEVICE_CLASSES
|
||||||
|
):
|
||||||
|
return True
|
||||||
|
|
||||||
|
if domain == "sensor" and device_class in SUPPORTED_SENSOR_DEVICE_CLASSES:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class CloudGoogleConfig(AbstractConfig):
|
class CloudGoogleConfig(AbstractConfig):
|
||||||
"""HA Cloud Configuration for Google Assistant."""
|
"""HA Cloud Configuration for Google Assistant."""
|
||||||
|
|
||||||
@ -180,9 +250,13 @@ class CloudGoogleConfig(AbstractConfig):
|
|||||||
|
|
||||||
# Backwards compat
|
# Backwards compat
|
||||||
if default_expose is None:
|
if default_expose is None:
|
||||||
return not auxiliary_entity
|
return not auxiliary_entity and _supported_legacy(self.hass, entity_id)
|
||||||
|
|
||||||
return not auxiliary_entity and split_entity_id(entity_id)[0] in default_expose
|
return (
|
||||||
|
not auxiliary_entity
|
||||||
|
and split_entity_id(entity_id)[0] in default_expose
|
||||||
|
and _supported_legacy(self.hass, entity_id)
|
||||||
|
)
|
||||||
|
|
||||||
def _should_expose_entity_id(self, entity_id):
|
def _should_expose_entity_id(self, entity_id):
|
||||||
"""If an entity should be exposed."""
|
"""If an entity should be exposed."""
|
||||||
|
@ -611,3 +611,106 @@ async def test_google_config_migrate_expose_entity_prefs_default_none(
|
|||||||
|
|
||||||
entity_default = entity_registry.async_get(entity_default.entity_id)
|
entity_default = entity_registry.async_get(entity_default.entity_id)
|
||||||
assert entity_default.options == {"cloud.google_assistant": {"should_expose": True}}
|
assert entity_default.options == {"cloud.google_assistant": {"should_expose": True}}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_google_config_migrate_expose_entity_prefs_default(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
cloud_prefs: CloudPreferences,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test migrating Google entity config."""
|
||||||
|
|
||||||
|
assert await async_setup_component(hass, "homeassistant", {})
|
||||||
|
|
||||||
|
binary_sensor_supported = entity_registry.async_get_or_create(
|
||||||
|
"binary_sensor",
|
||||||
|
"test",
|
||||||
|
"binary_sensor_supported",
|
||||||
|
original_device_class="door",
|
||||||
|
suggested_object_id="supported",
|
||||||
|
)
|
||||||
|
|
||||||
|
binary_sensor_unsupported = entity_registry.async_get_or_create(
|
||||||
|
"binary_sensor",
|
||||||
|
"test",
|
||||||
|
"binary_sensor_unsupported",
|
||||||
|
original_device_class="battery",
|
||||||
|
suggested_object_id="unsupported",
|
||||||
|
)
|
||||||
|
|
||||||
|
light = entity_registry.async_get_or_create(
|
||||||
|
"light",
|
||||||
|
"test",
|
||||||
|
"unique",
|
||||||
|
suggested_object_id="light",
|
||||||
|
)
|
||||||
|
|
||||||
|
sensor_supported = entity_registry.async_get_or_create(
|
||||||
|
"sensor",
|
||||||
|
"test",
|
||||||
|
"sensor_supported",
|
||||||
|
original_device_class="temperature",
|
||||||
|
suggested_object_id="supported",
|
||||||
|
)
|
||||||
|
|
||||||
|
sensor_unsupported = entity_registry.async_get_or_create(
|
||||||
|
"sensor",
|
||||||
|
"test",
|
||||||
|
"sensor_unsupported",
|
||||||
|
original_device_class="battery",
|
||||||
|
suggested_object_id="unsupported",
|
||||||
|
)
|
||||||
|
|
||||||
|
water_heater = entity_registry.async_get_or_create(
|
||||||
|
"water_heater",
|
||||||
|
"test",
|
||||||
|
"unique",
|
||||||
|
suggested_object_id="water_heater",
|
||||||
|
)
|
||||||
|
|
||||||
|
await cloud_prefs.async_update(
|
||||||
|
google_enabled=True,
|
||||||
|
google_report_state=False,
|
||||||
|
google_settings_version=1,
|
||||||
|
)
|
||||||
|
|
||||||
|
cloud_prefs._prefs[PREF_GOOGLE_DEFAULT_EXPOSE] = [
|
||||||
|
"binary_sensor",
|
||||||
|
"light",
|
||||||
|
"sensor",
|
||||||
|
"water_heater",
|
||||||
|
]
|
||||||
|
conf = CloudGoogleConfig(
|
||||||
|
hass, GACTIONS_SCHEMA({}), "mock-user-id", cloud_prefs, Mock(is_logged_in=False)
|
||||||
|
)
|
||||||
|
await conf.async_initialize()
|
||||||
|
|
||||||
|
binary_sensor_supported = entity_registry.async_get(
|
||||||
|
binary_sensor_supported.entity_id
|
||||||
|
)
|
||||||
|
assert binary_sensor_supported.options == {
|
||||||
|
"cloud.google_assistant": {"should_expose": True}
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_sensor_unsupported = entity_registry.async_get(
|
||||||
|
binary_sensor_unsupported.entity_id
|
||||||
|
)
|
||||||
|
assert binary_sensor_unsupported.options == {
|
||||||
|
"cloud.google_assistant": {"should_expose": False}
|
||||||
|
}
|
||||||
|
|
||||||
|
light = entity_registry.async_get(light.entity_id)
|
||||||
|
assert light.options == {"cloud.google_assistant": {"should_expose": True}}
|
||||||
|
|
||||||
|
sensor_supported = entity_registry.async_get(sensor_supported.entity_id)
|
||||||
|
assert sensor_supported.options == {
|
||||||
|
"cloud.google_assistant": {"should_expose": True}
|
||||||
|
}
|
||||||
|
|
||||||
|
sensor_unsupported = entity_registry.async_get(sensor_unsupported.entity_id)
|
||||||
|
assert sensor_unsupported.options == {
|
||||||
|
"cloud.google_assistant": {"should_expose": False}
|
||||||
|
}
|
||||||
|
|
||||||
|
water_heater = entity_registry.async_get(water_heater.entity_id)
|
||||||
|
assert water_heater.options == {"cloud.google_assistant": {"should_expose": False}}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user