diff --git a/homeassistant/components/aranet/sensor.py b/homeassistant/components/aranet/sensor.py index 4596a7fd8af..6ac27b1652b 100644 --- a/homeassistant/components/aranet/sensor.py +++ b/homeassistant/components/aranet/sensor.py @@ -28,7 +28,7 @@ from homeassistant.const import ( UnitOfTime, ) from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity import DEVICE_CLASS_NAME, DeviceInfo +from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN @@ -105,13 +105,6 @@ def sensor_update_to_bluetooth_data_update( adv: Aranet4Advertisement, ) -> PassiveBluetoothDataUpdate: """Convert a sensor update to a Bluetooth data update.""" - entity_names: dict[PassiveBluetoothEntityKey, str | None] = {} - for key, desc in SENSOR_DESCRIPTIONS.items(): - # PassiveBluetoothDataUpdate does not support DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME in the entity descriptions. - assert desc.name is not DEVICE_CLASS_NAME - entity_names[_device_key_to_bluetooth_entity_key(adv.device, key)] = desc.name return PassiveBluetoothDataUpdate( devices={adv.device.address: _sensor_device_info_to_hass(adv)}, entity_descriptions={ @@ -124,7 +117,10 @@ def sensor_update_to_bluetooth_data_update( ) for key in SENSOR_DESCRIPTIONS }, - entity_names=entity_names, + entity_names={ + _device_key_to_bluetooth_entity_key(adv.device, key): desc.name + for key, desc in SENSOR_DESCRIPTIONS.items() + }, ) diff --git a/homeassistant/components/balboa/entity.py b/homeassistant/components/balboa/entity.py index 1b2c8d48f0b..e50c35db477 100644 --- a/homeassistant/components/balboa/entity.py +++ b/homeassistant/components/balboa/entity.py @@ -4,7 +4,7 @@ from __future__ import annotations from pybalboa import EVENT_UPDATE, SpaClient from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC -from homeassistant.helpers.entity import DeviceClassName, DeviceInfo, Entity +from homeassistant.helpers.entity import DeviceInfo, Entity from .const import DOMAIN @@ -12,9 +12,7 @@ from .const import DOMAIN class BalboaBaseEntity(Entity): """Balboa base entity.""" - def __init__( - self, client: SpaClient, name: str | DeviceClassName | None = None - ) -> None: + def __init__(self, client: SpaClient, name: str | None = None) -> None: """Initialize the control.""" mac = client.mac_address model = client.model diff --git a/homeassistant/components/bond/button.py b/homeassistant/components/bond/button.py index d3fc58a35be..32b76c6fcae 100644 --- a/homeassistant/components/bond/button.py +++ b/homeassistant/components/bond/button.py @@ -35,11 +35,6 @@ class BondButtonEntityDescription( ): """Class to describe a Bond Button entity.""" - # BondEntity does not support DEVICE_CLASS_NAME - # Restrict the type to satisfy the type checker and catch attempts - # to use DEVICE_CLASS_NAME in the entity descriptions. - name: str | None = None - STOP_BUTTON = BondButtonEntityDescription( key=Action.STOP, diff --git a/homeassistant/components/brunt/cover.py b/homeassistant/components/brunt/cover.py index 1df34929b1c..3fb328ab7fb 100644 --- a/homeassistant/components/brunt/cover.py +++ b/homeassistant/components/brunt/cover.py @@ -88,7 +88,7 @@ class BruntDevice( self._attr_attribution = ATTRIBUTION self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, self._attr_unique_id)}, # type: ignore[arg-type] - name=self._thing.name, + name=self._attr_name, via_device=(DOMAIN, self._entry_id), manufacturer="Brunt", sw_version=self._thing.fw_version, diff --git a/homeassistant/components/freebox/home_base.py b/homeassistant/components/freebox/home_base.py index f10a9e047f7..c74f072a5be 100644 --- a/homeassistant/components/freebox/home_base.py +++ b/homeassistant/components/freebox/home_base.py @@ -30,8 +30,8 @@ class FreeboxHomeEntity(Entity): self._node = node self._sub_node = sub_node self._id = node["id"] - self._device_name = node["label"].strip() - self._attr_name = self._device_name + self._attr_name = node["label"].strip() + self._device_name = self._attr_name self._attr_unique_id = f"{self._router.mac}-node_{self._id}" if sub_node is not None: diff --git a/homeassistant/components/incomfort/sensor.py b/homeassistant/components/incomfort/sensor.py index 0205e690c42..b1b391aaaab 100644 --- a/homeassistant/components/incomfort/sensor.py +++ b/homeassistant/components/incomfort/sensor.py @@ -28,10 +28,6 @@ class IncomfortSensorEntityDescription(SensorEntityDescription): """Describes Incomfort sensor entity.""" extra_key: str | None = None - # IncomfortSensor does not support DEVICE_CLASS_NAME - # Restrict the type to satisfy the type checker and catch attempts - # to use DEVICE_CLASS_NAME in the entity descriptions. - name: str | None = None SENSOR_TYPES: tuple[IncomfortSensorEntityDescription, ...] = ( diff --git a/homeassistant/components/modbus/binary_sensor.py b/homeassistant/components/modbus/binary_sensor.py index f78e3ef9d31..4f416874f9d 100644 --- a/homeassistant/components/modbus/binary_sensor.py +++ b/homeassistant/components/modbus/binary_sensor.py @@ -14,7 +14,6 @@ from homeassistant.const import ( STATE_ON, ) from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers.entity import DEVICE_CLASS_NAME from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType @@ -74,11 +73,6 @@ class ModbusBinarySensor(BasePlatform, RestoreEntity, BinarySensorEntity): # this ensures that idx = bit position of value in result # polling is done with the base class name = self._attr_name if self._attr_name else "modbus_sensor" - - # DataUpdateCoordinator does not support DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME in _attr_name. - assert name is not DEVICE_CLASS_NAME self._coordinator = DataUpdateCoordinator( hass, _LOGGER, diff --git a/homeassistant/components/modbus/sensor.py b/homeassistant/components/modbus/sensor.py index 7c1c3b0a791..ca8246577fd 100644 --- a/homeassistant/components/modbus/sensor.py +++ b/homeassistant/components/modbus/sensor.py @@ -17,7 +17,6 @@ from homeassistant.const import ( CONF_UNIT_OF_MEASUREMENT, ) from homeassistant.core import HomeAssistant, callback -from homeassistant.helpers.entity import DEVICE_CLASS_NAME from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.update_coordinator import ( @@ -80,11 +79,6 @@ class ModbusRegisterSensor(BaseStructPlatform, RestoreSensor, SensorEntity): # this ensures that idx = bit position of value in result # polling is done with the base class name = self._attr_name if self._attr_name else "modbus_sensor" - - # DataUpdateCoordinator does not support DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME in _attr_name. - assert name is not DEVICE_CLASS_NAME self._coordinator = DataUpdateCoordinator( hass, _LOGGER, diff --git a/homeassistant/components/point/alarm_control_panel.py b/homeassistant/components/point/alarm_control_panel.py index 21469c2c5a5..bfffb934407 100644 --- a/homeassistant/components/point/alarm_control_panel.py +++ b/homeassistant/components/point/alarm_control_panel.py @@ -67,7 +67,7 @@ class MinutPointAlarmControl(AlarmControlPanelEntity): self._attr_device_info = DeviceInfo( identifiers={(POINT_DOMAIN, home_id)}, manufacturer="Minut", - name=self._home["name"], + name=self._attr_name, ) async def async_added_to_hass(self) -> None: diff --git a/homeassistant/components/shelly/utils.py b/homeassistant/components/shelly/utils.py index 6b781918b4f..55c08620e81 100644 --- a/homeassistant/components/shelly/utils.py +++ b/homeassistant/components/shelly/utils.py @@ -19,7 +19,6 @@ from homeassistant.helpers.device_registry import ( async_get as dr_async_get, format_mac, ) -from homeassistant.helpers.entity import DEVICE_CLASS_NAME, DeviceClassName from homeassistant.helpers.entity_registry import async_get as er_async_get from homeassistant.helpers.typing import EventType from homeassistant.util.dt import utcnow @@ -73,16 +72,12 @@ def get_number_of_channels(device: BlockDevice, block: Block) -> int: def get_block_entity_name( device: BlockDevice, block: Block | None, - description: str | DeviceClassName | None = None, + description: str | None = None, ) -> str: """Naming for block based switch and sensors.""" channel_name = get_block_channel_name(device, block) if description: - # It's not possible to do string manipulations on DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME as description. - assert description is not DEVICE_CLASS_NAME return f"{channel_name} {description.lower()}" return channel_name @@ -306,16 +301,12 @@ def get_rpc_channel_name(device: RpcDevice, key: str) -> str: def get_rpc_entity_name( - device: RpcDevice, key: str, description: str | DeviceClassName | None = None + device: RpcDevice, key: str, description: str | None = None ) -> str: """Naming for RPC based switch and sensors.""" channel_name = get_rpc_channel_name(device, key) if description: - # It's not possible to do string manipulations on DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME as description. - assert description is not DEVICE_CLASS_NAME return f"{channel_name} {description.lower()}" return channel_name diff --git a/homeassistant/components/system_bridge/__init__.py b/homeassistant/components/system_bridge/__init__.py index 1c5d4a4204e..05e607d56ed 100644 --- a/homeassistant/components/system_bridge/__init__.py +++ b/homeassistant/components/system_bridge/__init__.py @@ -30,7 +30,7 @@ from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers import config_validation as cv, device_registry as dr from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.entity import DEVICE_CLASS_NAME, DeviceClassName, DeviceInfo +from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN, MODULES @@ -279,17 +279,13 @@ class SystemBridgeEntity(CoordinatorEntity[SystemBridgeDataUpdateCoordinator]): coordinator: SystemBridgeDataUpdateCoordinator, api_port: int, key: str, - name: str | DeviceClassName | None, + name: str | None, ) -> None: """Initialize the System Bridge entity.""" super().__init__(coordinator) self._hostname = coordinator.data.system.hostname self._key = f"{self._hostname}_{key}" - # It's not possible to do string manipulations on DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME as name. - assert name is not DEVICE_CLASS_NAME self._name = f"{self._hostname} {name}" self._configuration_url = ( f"http://{self._hostname}:{api_port}/app/settings.html" diff --git a/homeassistant/components/tomorrowio/sensor.py b/homeassistant/components/tomorrowio/sensor.py index 23218543744..2b7d466d2f0 100644 --- a/homeassistant/components/tomorrowio/sensor.py +++ b/homeassistant/components/tomorrowio/sensor.py @@ -32,7 +32,6 @@ from homeassistant.const import ( UnitOfTemperature, ) from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity import DEVICE_CLASS_NAME from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util import slugify from homeassistant.util.unit_conversion import DistanceConverter, SpeedConverter @@ -350,10 +349,6 @@ class BaseTomorrowioSensorEntity(TomorrowioEntity, SensorEntity): """Initialize Tomorrow.io Sensor Entity.""" super().__init__(config_entry, coordinator, api_version) self.entity_description = description - # It's not possible to do string manipulations on DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME in the entity descriptions. - assert description.name is not DEVICE_CLASS_NAME self._attr_name = f"{self._config_entry.data[CONF_NAME]} - {description.name}" self._attr_unique_id = ( f"{self._config_entry.unique_id}_{slugify(description.name)}" diff --git a/homeassistant/components/unifiprotect/entity.py b/homeassistant/components/unifiprotect/entity.py index 9ca27c7174e..134b55c4b0d 100644 --- a/homeassistant/components/unifiprotect/entity.py +++ b/homeassistant/components/unifiprotect/entity.py @@ -22,12 +22,7 @@ from pyunifiprotect.data import ( from homeassistant.core import callback import homeassistant.helpers.device_registry as dr -from homeassistant.helpers.entity import ( - DEVICE_CLASS_NAME, - DeviceInfo, - Entity, - EntityDescription, -) +from homeassistant.helpers.entity import DeviceInfo, Entity, EntityDescription from .const import ( ATTR_EVENT_ID, @@ -204,10 +199,6 @@ class ProtectDeviceEntity(Entity): self.entity_description = description self._attr_unique_id = f"{self.device.mac}_{description.key}" name = description.name or "" - # It's not possible to do string manipulations on DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME in the entity descriptions. - assert name is not DEVICE_CLASS_NAME self._attr_name = f"{self.device.display_name} {name.title()}" self._attr_attribution = DEFAULT_ATTRIBUTION diff --git a/homeassistant/components/vizio/media_player.py b/homeassistant/components/vizio/media_player.py index bf52f053b32..a989cea488f 100644 --- a/homeassistant/components/vizio/media_player.py +++ b/homeassistant/components/vizio/media_player.py @@ -131,8 +131,6 @@ async def async_setup_entry( class VizioDevice(MediaPlayerEntity): """Media Player implementation which performs REST requests to device.""" - _attr_name: str - def __init__( self, config_entry: ConfigEntry, diff --git a/homeassistant/components/wemo/sensor.py b/homeassistant/components/wemo/sensor.py index 3cfc9a16f30..634d4a9e41d 100644 --- a/homeassistant/components/wemo/sensor.py +++ b/homeassistant/components/wemo/sensor.py @@ -28,10 +28,6 @@ from .wemo_device import DeviceCoordinator class AttributeSensorDescription(SensorEntityDescription): """SensorEntityDescription for WeMo AttributeSensor entities.""" - # AttributeSensor does not support DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME in the entity descriptions. - name: str | None = None state_conversion: Callable[[StateType], StateType] | None = None unique_id_suffix: str | None = None diff --git a/homeassistant/components/zwave_js/entity.py b/homeassistant/components/zwave_js/entity.py index 08e997170d7..6fe1a94b896 100644 --- a/homeassistant/components/zwave_js/entity.py +++ b/homeassistant/components/zwave_js/entity.py @@ -8,7 +8,7 @@ from zwave_js_server.model.value import Value as ZwaveValue, get_value_id_str from homeassistant.config_entries import ConfigEntry from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.helpers.entity import DEVICE_CLASS_NAME, DeviceInfo, Entity +from homeassistant.helpers.entity import DeviceInfo, Entity from .const import DOMAIN, LOGGER from .discovery import ZwaveDiscoveryInfo @@ -149,10 +149,6 @@ class ZWaveBaseEntity(Entity): and self.entity_description and self.entity_description.name ): - # It's not possible to do string manipulations on DEVICE_CLASS_NAME - # the assert satisfies the type checker and will catch attempts - # to use DEVICE_CLASS_NAME in the entity descriptions. - assert self.entity_description.name is not DEVICE_CLASS_NAME name = self.entity_description.name if name_prefix: diff --git a/homeassistant/components/zwave_me/__init__.py b/homeassistant/components/zwave_me/__init__.py index f49d203cb26..1740820d0ba 100644 --- a/homeassistant/components/zwave_me/__init__.py +++ b/homeassistant/components/zwave_me/__init__.py @@ -115,7 +115,7 @@ async def async_setup_platforms( class ZWaveMeEntity(Entity): """Representation of a ZWaveMe device.""" - def __init__(self, controller: ZWaveMeController, device: ZWaveMeData) -> None: + def __init__(self, controller, device): """Initialize the device.""" self.controller = controller self.device = device @@ -124,9 +124,13 @@ class ZWaveMeEntity(Entity): f"{self.controller.config.unique_id}-{self.device.id}" ) self._attr_should_poll = False - self._attr_device_info = DeviceInfo( + + @property + def device_info(self) -> DeviceInfo: + """Return device specific attributes.""" + return DeviceInfo( identifiers={(DOMAIN, self.device.deviceIdentifier)}, - name=device.title, + name=self._attr_name, manufacturer=self.device.manufacturer, sw_version=self.device.firmware, suggested_area=self.device.locationName, diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index 3cc655a7fd1..00171350594 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -52,16 +52,6 @@ DATA_ENTITY_SOURCE = "entity_info" SOURCE_CONFIG_ENTRY = "config_entry" SOURCE_PLATFORM_CONFIG = "platform_config" - -class DeviceClassName(Enum): - """Singleton to use device class name.""" - - _singleton = 0 - - -DEVICE_CLASS_NAME = DeviceClassName._singleton # pylint: disable=protected-access - - # Used when converting float states to string: limit precision according to machine # epsilon to make the string representation readable FLOAT_PRECISION = abs(int(math.floor(math.log10(abs(sys.float_info.epsilon))))) - 1 @@ -229,7 +219,7 @@ class EntityDescription: force_update: bool = False icon: str | None = None has_entity_name: bool = False - name: str | DeviceClassName | None = None + name: str | None = None translation_key: str | None = None unit_of_measurement: str | None = None @@ -298,7 +288,7 @@ class Entity(ABC): _attr_extra_state_attributes: MutableMapping[str, Any] _attr_force_update: bool _attr_icon: str | None - _attr_name: str | DeviceClassName | None + _attr_name: str | None _attr_should_poll: bool = True _attr_state: StateType = STATE_UNKNOWN _attr_supported_features: int | None = None @@ -328,24 +318,10 @@ class Entity(ABC): return self.entity_description.has_entity_name return False - def _device_class_name(self) -> str | None: - """Return a translated name of the entity based on its device class.""" - assert self.platform - if not self.has_entity_name: - return None - device_class_key = self.device_class or "_" - name_translation_key = ( - f"component.{self.platform.domain}.entity_component." - f"{device_class_key}.name" - ) - return self.platform.component_translations.get(name_translation_key) - @property def name(self) -> str | None: """Return the name of the entity.""" if hasattr(self, "_attr_name"): - if self._attr_name is DEVICE_CLASS_NAME: - return self._device_class_name() return self._attr_name if self.translation_key is not None and self.has_entity_name: assert self.platform @@ -353,12 +329,10 @@ class Entity(ABC): f"component.{self.platform.platform_name}.entity.{self.platform.domain}" f".{self.translation_key}.name" ) - if name_translation_key in self.platform.platform_translations: - name: str = self.platform.platform_translations[name_translation_key] + if name_translation_key in self.platform.entity_translations: + name: str = self.platform.entity_translations[name_translation_key] return name if hasattr(self, "entity_description"): - if self.entity_description.name is DEVICE_CLASS_NAME: - return self._device_class_name() return self.entity_description.name return None diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index 4a2ff020fe2..372f541d4bd 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -125,8 +125,7 @@ class EntityPlatform: self.entity_namespace = entity_namespace self.config_entry: config_entries.ConfigEntry | None = None self.entities: dict[str, Entity] = {} - self.component_translations: dict[str, Any] = {} - self.platform_translations: dict[str, Any] = {} + self.entity_translations: dict[str, Any] = {} self._tasks: list[asyncio.Task[None]] = [] # Stop tracking tasks after setup is completed self._setup_complete = False @@ -280,15 +279,7 @@ class EntityPlatform: full_name = f"{self.domain}.{self.platform_name}" try: - self.component_translations = await translation.async_get_translations( - hass, hass.config.language, "entity_component", {self.domain} - ) - except Exception as err: # pylint: disable=broad-exception-caught - _LOGGER.debug( - "Could not load translations for %s", self.domain, exc_info=err - ) - try: - self.platform_translations = await translation.async_get_translations( + self.entity_translations = await translation.async_get_translations( hass, hass.config.language, "entity", {self.platform_name} ) except Exception as err: # pylint: disable=broad-exception-caught diff --git a/homeassistant/helpers/template_entity.py b/homeassistant/helpers/template_entity.py index 2b2774eea66..c4eb8a1343d 100644 --- a/homeassistant/helpers/template_entity.py +++ b/homeassistant/helpers/template_entity.py @@ -172,8 +172,6 @@ class _TemplateAttribute: class TemplateEntity(Entity): """Entity that uses templates to calculate attributes.""" - _attr_name: str | None - _attr_available = True _attr_entity_picture = None _attr_icon = None diff --git a/tests/components/esphome/conftest.py b/tests/components/esphome/conftest.py index 381b9e99f03..4c01c2f7c5a 100644 --- a/tests/components/esphome/conftest.py +++ b/tests/components/esphome/conftest.py @@ -1,10 +1,9 @@ """esphome session fixtures.""" from __future__ import annotations -from asyncio import Event from unittest.mock import AsyncMock, Mock, patch -from aioesphomeapi import APIClient, APIVersion, DeviceInfo, ReconnectLogic +from aioesphomeapi import APIClient, APIVersion, DeviceInfo import pytest from zeroconf import Zeroconf @@ -159,18 +158,10 @@ async def mock_voice_assistant_v1_entry( mock_client.device_info = AsyncMock(return_value=device_info) mock_client.subscribe_voice_assistant = AsyncMock(return_value=Mock()) - try_connect_done = Event() - real_try_connect = ReconnectLogic._try_connect - - async def mock_try_connect(self): - """Set an event when ReconnectLogic._try_connect has been awaited.""" - result = await real_try_connect(self) - try_connect_done.set() - return result - - with patch.object(ReconnectLogic, "_try_connect", mock_try_connect): - await hass.config_entries.async_setup(entry.entry_id) - await try_connect_done.wait() + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + await hass.async_block_till_done() + await hass.async_block_till_done() return entry