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:
parent
8c5832ae82
commit
a0a8b9db26
12 changed files with 66 additions and 64 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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"],
|
||||
|
|
|
@ -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"}]}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue