Add entity category 'system' (#58595)

* Add entity category 'hidden'

* Update cloud

* Update Google assistant

* Update Alexa

* Fix tests

* Add ENTITY_CATEGORIES constant

* Rename ENTITY_CATEGORY_HIDDEN to ENTITY_CATEGORY_SYSTEM

* Correct import in motioneye
This commit is contained in:
Erik Montnemery 2021-10-28 14:36:41 +02:00 committed by GitHub
parent 8c5832ae82
commit a0a8b9db26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 66 additions and 64 deletions

View file

@ -3,12 +3,7 @@ import logging
from homeassistant import core
from homeassistant.components.http.view import HomeAssistantView
from homeassistant.const import (
CONF_CLIENT_ID,
CONF_CLIENT_SECRET,
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
from homeassistant.const import CONF_CLIENT_ID, CONF_CLIENT_SECRET, ENTITY_CATEGORIES
from homeassistant.helpers import entity_registry as er
from .auth import Auth
@ -71,10 +66,7 @@ class AlexaConfig(AbstractConfig):
entity_registry = er.async_get(self.hass)
if registry_entry := entity_registry.async_get(entity_id):
auxiliary_entity = registry_entry.entity_category in (
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
auxiliary_entity = registry_entry.entity_category in ENTITY_CATEGORIES
else:
auxiliary_entity = False
return not auxiliary_entity

View file

@ -16,11 +16,7 @@ from homeassistant.components.alexa import (
errors as alexa_errors,
state_report as alexa_state_report,
)
from homeassistant.const import (
CLOUD_NEVER_EXPOSED_ENTITIES,
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, ENTITY_CATEGORIES
from homeassistant.core import HomeAssistant, callback, split_entity_id
from homeassistant.helpers import entity_registry as er, start
from homeassistant.helpers.event import async_call_later
@ -135,10 +131,7 @@ class AlexaConfig(alexa_config.AbstractConfig):
entity_registry = er.async_get(self.hass)
if registry_entry := entity_registry.async_get(entity_id):
auxiliary_entity = registry_entry.entity_category in (
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
auxiliary_entity = registry_entry.entity_category in ENTITY_CATEGORIES
else:
auxiliary_entity = False

View file

@ -8,11 +8,7 @@ from hass_nabucasa.google_report_state import ErrorResponse
from homeassistant.components.google_assistant.const import DOMAIN as GOOGLE_DOMAIN
from homeassistant.components.google_assistant.helpers import AbstractConfig
from homeassistant.const import (
CLOUD_NEVER_EXPOSED_ENTITIES,
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, ENTITY_CATEGORIES
from homeassistant.core import CoreState, split_entity_id
from homeassistant.helpers import entity_registry as er, start
from homeassistant.setup import async_setup_component
@ -133,10 +129,7 @@ class CloudGoogleConfig(AbstractConfig):
entity_registry = er.async_get(self.hass)
if registry_entry := entity_registry.async_get(entity_id):
auxiliary_entity = registry_entry.entity_category in (
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
auxiliary_entity = registry_entry.entity_category in ENTITY_CATEGORIES
else:
auxiliary_entity = False

View file

@ -22,6 +22,7 @@ from homeassistant.const import (
ENERGY_KILO_WATT_HOUR,
ENERGY_MEGA_WATT_HOUR,
ENERGY_WATT_HOUR,
ENTITY_CATEGORY_SYSTEM,
VOLUME_CUBIC_METERS,
)
from homeassistant.core import (
@ -215,6 +216,7 @@ class EnergyCostSensor(SensorEntity):
utility.
"""
_attr_entity_category = ENTITY_CATEGORY_SYSTEM
_wrong_state_class_reported = False
_wrong_unit_reported = False

View file

@ -11,11 +11,7 @@ import jwt
# Typing imports
from homeassistant.components.http import HomeAssistantView
from homeassistant.const import (
CLOUD_NEVER_EXPOSED_ENTITIES,
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, ENTITY_CATEGORIES
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.util import dt as dt_util
@ -117,10 +113,7 @@ class GoogleConfig(AbstractConfig):
entity_registry = er.async_get(self.hass)
registry_entry = entity_registry.async_get(state.entity_id)
if registry_entry:
auxiliary_entity = registry_entry.entity_category in (
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
)
auxiliary_entity = registry_entry.entity_category in ENTITY_CATEGORIES
else:
auxiliary_entity = False

View file

@ -17,8 +17,8 @@ from motioneye_client.const import (
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ENTITY_CATEGORY_CONFIG
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import ENTITY_CATEGORY_CONFIG
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator

View file

@ -714,3 +714,13 @@ CAST_APP_ID_HOMEASSISTANT: Final = "B12CE3CA"
ENTITY_CATEGORY_CONFIG: Final = "config"
ENTITY_CATEGORY_DIAGNOSTIC: Final = "diagnostic"
ENTITY_CATEGORY_SYSTEM: Final = "system"
# Entity categories which will:
# - Not be exposed to cloud, alexa, or google_home components
# - Not be included in indirect service calls to devices or areas
ENTITY_CATEGORIES: Final[list[str]] = [
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
ENTITY_CATEGORY_SYSTEM,
]

View file

@ -26,8 +26,7 @@ from homeassistant.const import (
ATTR_SUPPORTED_FEATURES,
ATTR_UNIT_OF_MEASUREMENT,
DEVICE_DEFAULT_NAME,
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
ENTITY_CATEGORIES,
STATE_OFF,
STATE_ON,
STATE_UNAVAILABLE,
@ -56,11 +55,6 @@ SOURCE_PLATFORM_CONFIG = "platform_config"
FLOAT_PRECISION = abs(int(math.floor(math.log10(abs(sys.float_info.epsilon))))) - 1
ENTITY_CATEGORIES: Final[list[str]] = [
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
]
ENTITY_CATEGORIES_SCHEMA: Final = vol.In(ENTITY_CATEGORIES)
@ -193,7 +187,7 @@ class EntityDescription:
key: str
device_class: str | None = None
entity_category: Literal["config", "diagnostic"] | None = None
entity_category: Literal["config", "diagnostic", "system"] | None = None
entity_registry_enabled_default: bool = True
force_update: bool = False
icon: str | None = None

View file

@ -20,8 +20,7 @@ from homeassistant.const import (
CONF_SERVICE_DATA,
CONF_SERVICE_TEMPLATE,
CONF_TARGET,
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
ENTITY_CATEGORIES,
ENTITY_MATCH_ALL,
ENTITY_MATCH_NONE,
)
@ -367,10 +366,7 @@ def async_extract_referenced_entity_ids(
for ent_entry in ent_reg.entities.values():
# Do not add config or diagnostic entities referenced by areas or devices
if ent_entry.entity_category in (
ENTITY_CATEGORY_CONFIG,
ENTITY_CATEGORY_DIAGNOSTIC,
):
if ent_entry.entity_category in ENTITY_CATEGORIES:
continue
if (

View file

@ -22,19 +22,26 @@ async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs, cloud_stub):
entity_registry = mock_registry(hass)
entity_entry1 = entity_registry.async_get_or_create(
"switch",
"light",
"test",
"switch_config_id",
suggested_object_id="config_switch",
"light_config_id",
suggested_object_id="config_light",
entity_category="config",
)
entity_entry2 = entity_registry.async_get_or_create(
"switch",
"light",
"test",
"switch_diagnostic_id",
suggested_object_id="diagnostic_switch",
"light_diagnostic_id",
suggested_object_id="diagnostic_light",
entity_category="diagnostic",
)
entity_entry3 = entity_registry.async_get_or_create(
"light",
"test",
"light_system_id",
suggested_object_id="system_light",
entity_category="system",
)
entity_conf = {"should_expose": False}
await cloud_prefs.async_update(
@ -50,18 +57,21 @@ async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs, cloud_stub):
assert not conf.should_expose("light.kitchen")
assert not conf.should_expose(entity_entry1.entity_id)
assert not conf.should_expose(entity_entry2.entity_id)
assert not conf.should_expose(entity_entry3.entity_id)
entity_conf["should_expose"] = True
assert conf.should_expose("light.kitchen")
# config and diagnostic entities should not be exposed
assert not conf.should_expose(entity_entry1.entity_id)
assert not conf.should_expose(entity_entry2.entity_id)
assert not conf.should_expose(entity_entry3.entity_id)
entity_conf["should_expose"] = None
assert conf.should_expose("light.kitchen")
# config and diagnostic entities should not be exposed
assert not conf.should_expose(entity_entry1.entity_id)
assert not conf.should_expose(entity_entry2.entity_id)
assert not conf.should_expose(entity_entry3.entity_id)
assert "alexa" not in hass.config.components
await cloud_prefs.async_update(

View file

@ -223,19 +223,26 @@ async def test_google_config_expose_entity_prefs(hass, mock_conf, cloud_prefs):
entity_registry = mock_registry(hass)
entity_entry1 = entity_registry.async_get_or_create(
"switch",
"light",
"test",
"switch_config_id",
suggested_object_id="config_switch",
"light_config_id",
suggested_object_id="config_light",
entity_category="config",
)
entity_entry2 = entity_registry.async_get_or_create(
"switch",
"light",
"test",
"switch_diagnostic_id",
suggested_object_id="diagnostic_switch",
"light_diagnostic_id",
suggested_object_id="diagnostic_light",
entity_category="diagnostic",
)
entity_entry3 = entity_registry.async_get_or_create(
"light",
"test",
"light_system_id",
suggested_object_id="system_light",
entity_category="system",
)
entity_conf = {"should_expose": False}
await cloud_prefs.async_update(
@ -246,22 +253,26 @@ async def test_google_config_expose_entity_prefs(hass, mock_conf, cloud_prefs):
state = State("light.kitchen", "on")
state_config = State(entity_entry1.entity_id, "on")
state_diagnostic = State(entity_entry2.entity_id, "on")
state_system = State(entity_entry3.entity_id, "on")
assert not mock_conf.should_expose(state)
assert not mock_conf.should_expose(state_config)
assert not mock_conf.should_expose(state_diagnostic)
assert not mock_conf.should_expose(state_system)
entity_conf["should_expose"] = True
assert mock_conf.should_expose(state)
# config and diagnostic entities should not be exposed
assert not mock_conf.should_expose(state_config)
assert not mock_conf.should_expose(state_diagnostic)
assert not mock_conf.should_expose(state_system)
entity_conf["should_expose"] = None
assert mock_conf.should_expose(state)
# config and diagnostic entities should not be exposed
assert not mock_conf.should_expose(state_config)
assert not mock_conf.should_expose(state_diagnostic)
assert not mock_conf.should_expose(state_system)
await cloud_prefs.async_update(
google_default_expose=["sensor"],

View file

@ -144,10 +144,18 @@ async def test_sync_request(hass_fixture, assistant_client, auth_header):
suggested_object_id="diagnostic_switch",
entity_category="diagnostic",
)
entity_entry3 = entity_registry.async_get_or_create(
"switch",
"test",
"switch_system_id",
suggested_object_id="system_switch",
entity_category="system",
)
# These should not show up in the sync request
hass_fixture.states.async_set(entity_entry1.entity_id, "on")
hass_fixture.states.async_set(entity_entry2.entity_id, "something_else")
hass_fixture.states.async_set(entity_entry3.entity_id, "blah")
reqid = "5711642932632160983"
data = {"requestId": reqid, "inputs": [{"intent": "action.devices.SYNC"}]}