From 5dd787aa104c083eb8b6845248eca837e01fca12 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Mon, 6 Nov 2023 10:34:06 +0100 Subject: [PATCH] Validate entity category for binary_sensor (#103464) --- .../components/binary_sensor/__init__.py | 11 ++- tests/components/binary_sensor/test_init.py | 70 ++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/binary_sensor/__init__.py b/homeassistant/components/binary_sensor/__init__.py index 79e20c6f571..a84cbc18756 100644 --- a/homeassistant/components/binary_sensor/__init__.py +++ b/homeassistant/components/binary_sensor/__init__.py @@ -10,8 +10,9 @@ from typing import Literal, final import voluptuous as vol from homeassistant.config_entries import ConfigEntry -from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.config_validation import ( # noqa: F401 PLATFORM_SCHEMA, PLATFORM_SCHEMA_BASE, @@ -190,6 +191,14 @@ class BinarySensorEntity(Entity): _attr_is_on: bool | None = None _attr_state: None = None + async def async_internal_added_to_hass(self) -> None: + """Call when the binary sensor entity is added to hass.""" + await super().async_internal_added_to_hass() + if self.entity_category == EntityCategory.CONFIG: + raise HomeAssistantError( + f"Entity {self.entity_id} cannot be added as the entity category is set to config" + ) + def _default_to_device_class_name(self) -> bool: """Return True if an unnamed entity should be named by its device class. diff --git a/tests/components/binary_sensor/test_init.py b/tests/components/binary_sensor/test_init.py index a35a6c906df..437a2e1efa6 100644 --- a/tests/components/binary_sensor/test_init.py +++ b/tests/components/binary_sensor/test_init.py @@ -6,7 +6,7 @@ import pytest from homeassistant.components import binary_sensor from homeassistant.config_entries import ConfigEntry, ConfigFlow -from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -18,6 +18,7 @@ from tests.common import ( mock_integration, mock_platform, ) +from tests.testing_config.custom_components.test.binary_sensor import MockBinarySensor TEST_DOMAIN = "test" @@ -126,3 +127,70 @@ async def test_name(hass: HomeAssistant) -> None: state = hass.states.get(entity4.entity_id) assert state.attributes == {"device_class": "battery", "friendly_name": "Battery"} + + +async def test_entity_category_config_raises_error( + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test error is raised when entity category is set to config.""" + + async def async_setup_entry_init( + hass: HomeAssistant, config_entry: ConfigEntry + ) -> bool: + """Set up test config entry.""" + await hass.config_entries.async_forward_entry_setup( + config_entry, binary_sensor.DOMAIN + ) + return True + + mock_platform(hass, f"{TEST_DOMAIN}.config_flow") + mock_integration( + hass, + MockModule( + TEST_DOMAIN, + async_setup_entry=async_setup_entry_init, + ), + ) + + description1 = binary_sensor.BinarySensorEntityDescription( + "diagnostic", entity_category=EntityCategory.DIAGNOSTIC + ) + entity1 = MockBinarySensor() + entity1.entity_description = description1 + entity1.entity_id = "binary_sensor.test1" + + description2 = binary_sensor.BinarySensorEntityDescription( + "config", entity_category=EntityCategory.CONFIG + ) + entity2 = MockBinarySensor() + entity2.entity_description = description2 + entity2.entity_id = "binary_sensor.test2" + + async def async_setup_entry_platform( + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, + ) -> None: + """Set up test stt platform via config entry.""" + async_add_entities([entity1, entity2]) + + mock_platform( + hass, + f"{TEST_DOMAIN}.{binary_sensor.DOMAIN}", + MockPlatform(async_setup_entry=async_setup_entry_platform), + ) + + config_entry = MockConfigEntry(domain=TEST_DOMAIN) + config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + state1 = hass.states.get("binary_sensor.test1") + assert state1 is not None + state2 = hass.states.get("binary_sensor.test2") + assert state2 is None + assert ( + "Entity binary_sensor.test2 cannot be added as the entity category is set to config" + in caplog.text + )