Name unnamed binary sensors by their device class (#92940)
* Name unnamed binary sensors by their device class * Update type annotations * Fix loading of entity component translations * Add test * Update integrations * Set abode and rfxtrx binary_sensor name to None * Revert changes in homekit_controller
This commit is contained in:
parent
223394eaee
commit
2406b235b4
27 changed files with 287 additions and 47 deletions
|
@ -42,6 +42,7 @@ async def async_setup_entry(
|
||||||
class AbodeBinarySensor(AbodeDevice, BinarySensorEntity):
|
class AbodeBinarySensor(AbodeDevice, BinarySensorEntity):
|
||||||
"""A binary sensor implementation for Abode device."""
|
"""A binary sensor implementation for Abode device."""
|
||||||
|
|
||||||
|
_attr_name = None
|
||||||
_device: ABBinarySensor
|
_device: ABBinarySensor
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"""Support for Aranet sensors."""
|
"""Support for Aranet sensors."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
from aranet4.client import Aranet4Advertisement
|
from aranet4.client import Aranet4Advertisement
|
||||||
from bleak.backends.device import BLEDevice
|
from bleak.backends.device import BLEDevice
|
||||||
|
|
||||||
|
@ -33,43 +35,54 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AranetSensorEntityDescription(SensorEntityDescription):
|
||||||
|
"""Class to describe an Aranet sensor entity."""
|
||||||
|
|
||||||
|
# PassiveBluetoothDataUpdate does not support UNDEFINED
|
||||||
|
# Restrict the type to satisfy the type checker and catch attempts
|
||||||
|
# to use UNDEFINED in the entity descriptions.
|
||||||
|
name: str | None = None
|
||||||
|
|
||||||
|
|
||||||
SENSOR_DESCRIPTIONS = {
|
SENSOR_DESCRIPTIONS = {
|
||||||
"temperature": SensorEntityDescription(
|
"temperature": AranetSensorEntityDescription(
|
||||||
key="temperature",
|
key="temperature",
|
||||||
name="Temperature",
|
name="Temperature",
|
||||||
device_class=SensorDeviceClass.TEMPERATURE,
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
"humidity": SensorEntityDescription(
|
"humidity": AranetSensorEntityDescription(
|
||||||
key="humidity",
|
key="humidity",
|
||||||
name="Humidity",
|
name="Humidity",
|
||||||
device_class=SensorDeviceClass.HUMIDITY,
|
device_class=SensorDeviceClass.HUMIDITY,
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
"pressure": SensorEntityDescription(
|
"pressure": AranetSensorEntityDescription(
|
||||||
key="pressure",
|
key="pressure",
|
||||||
name="Pressure",
|
name="Pressure",
|
||||||
device_class=SensorDeviceClass.PRESSURE,
|
device_class=SensorDeviceClass.PRESSURE,
|
||||||
native_unit_of_measurement=UnitOfPressure.HPA,
|
native_unit_of_measurement=UnitOfPressure.HPA,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
"co2": SensorEntityDescription(
|
"co2": AranetSensorEntityDescription(
|
||||||
key="co2",
|
key="co2",
|
||||||
name="Carbon Dioxide",
|
name="Carbon Dioxide",
|
||||||
device_class=SensorDeviceClass.CO2,
|
device_class=SensorDeviceClass.CO2,
|
||||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
"battery": SensorEntityDescription(
|
"battery": AranetSensorEntityDescription(
|
||||||
key="battery",
|
key="battery",
|
||||||
name="Battery",
|
name="Battery",
|
||||||
device_class=SensorDeviceClass.BATTERY,
|
device_class=SensorDeviceClass.BATTERY,
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
),
|
),
|
||||||
"interval": SensorEntityDescription(
|
"interval": AranetSensorEntityDescription(
|
||||||
key="update_interval",
|
key="update_interval",
|
||||||
name="Update Interval",
|
name="Update Interval",
|
||||||
device_class=SensorDeviceClass.DURATION,
|
device_class=SensorDeviceClass.DURATION,
|
||||||
|
|
|
@ -5,7 +5,6 @@ from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
from typing import cast
|
|
||||||
|
|
||||||
from yalexs.activity import (
|
from yalexs.activity import (
|
||||||
ACTION_DOORBELL_CALL_MISSED,
|
ACTION_DOORBELL_CALL_MISSED,
|
||||||
|
@ -104,7 +103,16 @@ def _native_datetime() -> datetime:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AugustRequiredKeysMixin:
|
class AugustBinarySensorEntityDescription(BinarySensorEntityDescription):
|
||||||
|
"""Describes August binary_sensor entity."""
|
||||||
|
|
||||||
|
# AugustBinarySensor does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AugustDoorbellRequiredKeysMixin:
|
||||||
"""Mixin for required keys."""
|
"""Mixin for required keys."""
|
||||||
|
|
||||||
value_fn: Callable[[AugustData, DoorbellDetail], bool]
|
value_fn: Callable[[AugustData, DoorbellDetail], bool]
|
||||||
|
@ -112,41 +120,45 @@ class AugustRequiredKeysMixin:
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class AugustBinarySensorEntityDescription(
|
class AugustDoorbellBinarySensorEntityDescription(
|
||||||
BinarySensorEntityDescription, AugustRequiredKeysMixin
|
BinarySensorEntityDescription, AugustDoorbellRequiredKeysMixin
|
||||||
):
|
):
|
||||||
"""Describes August binary_sensor entity."""
|
"""Describes August binary_sensor entity."""
|
||||||
|
|
||||||
|
# AugustDoorbellBinarySensor does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
SENSOR_TYPE_DOOR = BinarySensorEntityDescription(
|
|
||||||
|
SENSOR_TYPE_DOOR = AugustBinarySensorEntityDescription(
|
||||||
key="door_open",
|
key="door_open",
|
||||||
name="Open",
|
name="Open",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
SENSOR_TYPES_DOORBELL: tuple[AugustBinarySensorEntityDescription, ...] = (
|
SENSOR_TYPES_DOORBELL: tuple[AugustDoorbellBinarySensorEntityDescription, ...] = (
|
||||||
AugustBinarySensorEntityDescription(
|
AugustDoorbellBinarySensorEntityDescription(
|
||||||
key="doorbell_ding",
|
key="doorbell_ding",
|
||||||
name="Ding",
|
name="Ding",
|
||||||
device_class=BinarySensorDeviceClass.OCCUPANCY,
|
device_class=BinarySensorDeviceClass.OCCUPANCY,
|
||||||
value_fn=_retrieve_ding_state,
|
value_fn=_retrieve_ding_state,
|
||||||
is_time_based=True,
|
is_time_based=True,
|
||||||
),
|
),
|
||||||
AugustBinarySensorEntityDescription(
|
AugustDoorbellBinarySensorEntityDescription(
|
||||||
key="doorbell_motion",
|
key="doorbell_motion",
|
||||||
name="Motion",
|
name="Motion",
|
||||||
device_class=BinarySensorDeviceClass.MOTION,
|
device_class=BinarySensorDeviceClass.MOTION,
|
||||||
value_fn=_retrieve_motion_state,
|
value_fn=_retrieve_motion_state,
|
||||||
is_time_based=True,
|
is_time_based=True,
|
||||||
),
|
),
|
||||||
AugustBinarySensorEntityDescription(
|
AugustDoorbellBinarySensorEntityDescription(
|
||||||
key="doorbell_image_capture",
|
key="doorbell_image_capture",
|
||||||
name="Image Capture",
|
name="Image Capture",
|
||||||
icon="mdi:file-image",
|
icon="mdi:file-image",
|
||||||
value_fn=_retrieve_image_capture_state,
|
value_fn=_retrieve_image_capture_state,
|
||||||
is_time_based=True,
|
is_time_based=True,
|
||||||
),
|
),
|
||||||
AugustBinarySensorEntityDescription(
|
AugustDoorbellBinarySensorEntityDescription(
|
||||||
key="doorbell_online",
|
key="doorbell_online",
|
||||||
name="Online",
|
name="Online",
|
||||||
device_class=BinarySensorDeviceClass.CONNECTIVITY,
|
device_class=BinarySensorDeviceClass.CONNECTIVITY,
|
||||||
|
@ -199,7 +211,10 @@ class AugustDoorBinarySensor(AugustEntityMixin, BinarySensorEntity):
|
||||||
_attr_device_class = BinarySensorDeviceClass.DOOR
|
_attr_device_class = BinarySensorDeviceClass.DOOR
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, data: AugustData, device: Lock, description: BinarySensorEntityDescription
|
self,
|
||||||
|
data: AugustData,
|
||||||
|
device: Lock,
|
||||||
|
description: AugustBinarySensorEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
super().__init__(data, device)
|
super().__init__(data, device)
|
||||||
|
@ -207,9 +222,7 @@ class AugustDoorBinarySensor(AugustEntityMixin, BinarySensorEntity):
|
||||||
self._data = data
|
self._data = data
|
||||||
self._device = device
|
self._device = device
|
||||||
self._attr_name = f"{device.device_name} {description.name}"
|
self._attr_name = f"{device.device_name} {description.name}"
|
||||||
self._attr_unique_id = (
|
self._attr_unique_id = f"{self._device_id}_{description.name.lower()}"
|
||||||
f"{self._device_id}_{cast(str, description.name).lower()}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_from_data(self):
|
def _update_from_data(self):
|
||||||
|
@ -243,13 +256,13 @@ class AugustDoorBinarySensor(AugustEntityMixin, BinarySensorEntity):
|
||||||
class AugustDoorbellBinarySensor(AugustEntityMixin, BinarySensorEntity):
|
class AugustDoorbellBinarySensor(AugustEntityMixin, BinarySensorEntity):
|
||||||
"""Representation of an August binary sensor."""
|
"""Representation of an August binary sensor."""
|
||||||
|
|
||||||
entity_description: AugustBinarySensorEntityDescription
|
entity_description: AugustDoorbellBinarySensorEntityDescription
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
data: AugustData,
|
data: AugustData,
|
||||||
device: Doorbell,
|
device: Doorbell,
|
||||||
description: AugustBinarySensorEntityDescription,
|
description: AugustDoorbellBinarySensorEntityDescription,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the sensor."""
|
"""Initialize the sensor."""
|
||||||
super().__init__(data, device)
|
super().__init__(data, device)
|
||||||
|
@ -257,9 +270,7 @@ class AugustDoorbellBinarySensor(AugustEntityMixin, BinarySensorEntity):
|
||||||
self._check_for_off_update_listener = None
|
self._check_for_off_update_listener = None
|
||||||
self._data = data
|
self._data = data
|
||||||
self._attr_name = f"{device.device_name} {description.name}"
|
self._attr_name = f"{device.device_name} {description.name}"
|
||||||
self._attr_unique_id = (
|
self._attr_unique_id = f"{self._device_id}_{description.name.lower()}"
|
||||||
f"{self._device_id}_{cast(str, description.name).lower()}"
|
|
||||||
)
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _update_from_data(self):
|
def _update_from_data(self):
|
||||||
|
|
|
@ -47,6 +47,10 @@ class BalboaBinarySensorEntityDescription(
|
||||||
):
|
):
|
||||||
"""A class that describes Balboa binary sensor entities."""
|
"""A class that describes Balboa binary sensor entities."""
|
||||||
|
|
||||||
|
# BalboaBinarySensorEntity does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
|
|
||||||
FILTER_CYCLE_ICONS = ("mdi:sync", "mdi:sync-off")
|
FILTER_CYCLE_ICONS = ("mdi:sync", "mdi:sync-off")
|
||||||
BINARY_SENSOR_DESCRIPTIONS = (
|
BINARY_SENSOR_DESCRIPTIONS = (
|
||||||
|
|
|
@ -190,6 +190,13 @@ class BinarySensorEntity(Entity):
|
||||||
_attr_is_on: bool | None = None
|
_attr_is_on: bool | None = None
|
||||||
_attr_state: None = None
|
_attr_state: None = None
|
||||||
|
|
||||||
|
def _default_to_device_class_name(self) -> bool:
|
||||||
|
"""Return True if an unnamed entity should be named by its device class.
|
||||||
|
|
||||||
|
For binary sensors this is True if the entity has a device class.
|
||||||
|
"""
|
||||||
|
return self.device_class is not None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self) -> BinarySensorDeviceClass | None:
|
def device_class(self) -> BinarySensorDeviceClass | None:
|
||||||
"""Return the class of this entity."""
|
"""Return the class of this entity."""
|
||||||
|
|
|
@ -35,6 +35,10 @@ class BondButtonEntityDescription(
|
||||||
):
|
):
|
||||||
"""Class to describe a Bond Button entity."""
|
"""Class to describe a Bond Button entity."""
|
||||||
|
|
||||||
|
# BondEntity does not support UNDEFINED,
|
||||||
|
# restrict the type to str | None
|
||||||
|
name: str | None = None
|
||||||
|
|
||||||
|
|
||||||
STOP_BUTTON = BondButtonEntityDescription(
|
STOP_BUTTON = BondButtonEntityDescription(
|
||||||
key=Action.STOP,
|
key=Action.STOP,
|
||||||
|
|
|
@ -15,7 +15,7 @@ from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import UNDEFINED, StateType
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
|
@ -80,7 +80,7 @@ class EmonitorPowerSensor(CoordinatorEntity, SensorEntity):
|
||||||
mac_address = self.emonitor_status.network.mac_address
|
mac_address = self.emonitor_status.network.mac_address
|
||||||
device_name = name_short_mac(mac_address[-6:])
|
device_name = name_short_mac(mac_address[-6:])
|
||||||
label = self.channel_data.label or f"{device_name} {channel_number}"
|
label = self.channel_data.label or f"{device_name} {channel_number}"
|
||||||
if description.name:
|
if description.name is not UNDEFINED:
|
||||||
self._attr_name = f"{label} {description.name}"
|
self._attr_name = f"{label} {description.name}"
|
||||||
self._attr_unique_id = f"{mac_address}_{channel_number}_{description.key}"
|
self._attr_unique_id = f"{mac_address}_{channel_number}_{description.key}"
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -18,6 +18,7 @@ from homeassistant.const import UnitOfPower
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.entity import DeviceInfo
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import UNDEFINED
|
||||||
from homeassistant.helpers.update_coordinator import (
|
from homeassistant.helpers.update_coordinator import (
|
||||||
CoordinatorEntity,
|
CoordinatorEntity,
|
||||||
DataUpdateCoordinator,
|
DataUpdateCoordinator,
|
||||||
|
@ -168,7 +169,7 @@ class EnvoyInverter(CoordinatorEntity, SensorEntity):
|
||||||
"""Initialize Envoy inverter entity."""
|
"""Initialize Envoy inverter entity."""
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self._serial_number = serial_number
|
self._serial_number = serial_number
|
||||||
if description.name:
|
if description.name is not UNDEFINED:
|
||||||
self._attr_name = (
|
self._attr_name = (
|
||||||
f"{envoy_name} Inverter {serial_number} {description.name}"
|
f"{envoy_name} Inverter {serial_number} {description.name}"
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, cast
|
from typing import Any
|
||||||
|
|
||||||
from greeclimate.device import Device
|
from greeclimate.device import Device
|
||||||
|
|
||||||
|
@ -33,6 +33,10 @@ class GreeRequiredKeysMixin:
|
||||||
class GreeSwitchEntityDescription(SwitchEntityDescription, GreeRequiredKeysMixin):
|
class GreeSwitchEntityDescription(SwitchEntityDescription, GreeRequiredKeysMixin):
|
||||||
"""Describes Gree switch entity."""
|
"""Describes Gree switch entity."""
|
||||||
|
|
||||||
|
# GreeSwitch does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
|
|
||||||
def _set_light(device: Device, value: bool) -> None:
|
def _set_light(device: Device, value: bool) -> None:
|
||||||
"""Typed helper to set device light property."""
|
"""Typed helper to set device light property."""
|
||||||
|
@ -130,7 +134,7 @@ class GreeSwitch(GreeEntity, SwitchEntity):
|
||||||
"""Initialize the Gree device."""
|
"""Initialize the Gree device."""
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
|
|
||||||
super().__init__(coordinator, cast(str, description.name))
|
super().__init__(coordinator, description.name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
|
|
|
@ -117,6 +117,10 @@ class HuaweiSensorGroup:
|
||||||
class HuaweiSensorEntityDescription(SensorEntityDescription):
|
class HuaweiSensorEntityDescription(SensorEntityDescription):
|
||||||
"""Class describing Huawei LTE sensor entities."""
|
"""Class describing Huawei LTE sensor entities."""
|
||||||
|
|
||||||
|
# HuaweiLteSensor does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
format_fn: Callable[[str], tuple[StateType, str | None]] = format_default
|
format_fn: Callable[[str], tuple[StateType, str | None]] = format_default
|
||||||
icon_fn: Callable[[StateType], str] | None = None
|
icon_fn: Callable[[StateType], str] | None = None
|
||||||
device_class_fn: Callable[[StateType], SensorDeviceClass | None] | None = None
|
device_class_fn: Callable[[StateType], SensorDeviceClass | None] | None = None
|
||||||
|
|
|
@ -28,6 +28,9 @@ class IncomfortSensorEntityDescription(SensorEntityDescription):
|
||||||
"""Describes Incomfort sensor entity."""
|
"""Describes Incomfort sensor entity."""
|
||||||
|
|
||||||
extra_key: str | None = None
|
extra_key: str | None = None
|
||||||
|
# IncomfortSensor does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
|
|
||||||
SENSOR_TYPES: tuple[IncomfortSensorEntityDescription, ...] = (
|
SENSOR_TYPES: tuple[IncomfortSensorEntityDescription, ...] = (
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""Support for ISY switches."""
|
"""Support for ISY switches."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from pyisy.constants import (
|
from pyisy.constants import (
|
||||||
|
@ -22,7 +23,7 @@ from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import EntityCategory, Platform
|
from homeassistant.const import EntityCategory, Platform
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.entity import DeviceInfo, EntityDescription
|
from homeassistant.helpers.entity import DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
|
@ -30,6 +31,15 @@ from .entity import ISYAuxControlEntity, ISYNodeEntity, ISYProgramEntity
|
||||||
from .models import IsyData
|
from .models import IsyData
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ISYSwitchEntityDescription(SwitchEntityDescription):
|
||||||
|
"""Describes IST switch."""
|
||||||
|
|
||||||
|
# ISYEnableSwitchEntity does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -53,7 +63,7 @@ async def async_setup_entry(
|
||||||
for node, control in isy_data.aux_properties[Platform.SWITCH]:
|
for node, control in isy_data.aux_properties[Platform.SWITCH]:
|
||||||
# Currently only used for enable switches, will need to be updated for
|
# Currently only used for enable switches, will need to be updated for
|
||||||
# NS support by making sure control == TAG_ENABLED
|
# NS support by making sure control == TAG_ENABLED
|
||||||
description = SwitchEntityDescription(
|
description = ISYSwitchEntityDescription(
|
||||||
key=control,
|
key=control,
|
||||||
device_class=SwitchDeviceClass.SWITCH,
|
device_class=SwitchDeviceClass.SWITCH,
|
||||||
name=control.title(),
|
name=control.title(),
|
||||||
|
@ -135,7 +145,7 @@ class ISYEnableSwitchEntity(ISYAuxControlEntity, SwitchEntity):
|
||||||
node: Node,
|
node: Node,
|
||||||
control: str,
|
control: str,
|
||||||
unique_id: str,
|
unique_id: str,
|
||||||
description: EntityDescription,
|
description: ISYSwitchEntityDescription,
|
||||||
device_info: DeviceInfo | None,
|
device_info: DeviceInfo | None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the ISY Aux Control Number entity."""
|
"""Initialize the ISY Aux Control Number entity."""
|
||||||
|
|
|
@ -9,7 +9,7 @@ from homeassistant.components.sensor import SensorDeviceClass, SensorEntity
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
from homeassistant.helpers.typing import UNDEFINED, ConfigType, DiscoveryInfoType
|
||||||
|
|
||||||
from . import REPETIER_API, SENSOR_TYPES, UPDATE_SIGNAL, RepetierSensorEntityDescription
|
from . import REPETIER_API, SENSOR_TYPES, UPDATE_SIGNAL, RepetierSensorEntityDescription
|
||||||
|
|
||||||
|
@ -45,7 +45,8 @@ def setup_platform(
|
||||||
sensor_type = info["sensor_type"]
|
sensor_type = info["sensor_type"]
|
||||||
temp_id = info["temp_id"]
|
temp_id = info["temp_id"]
|
||||||
description = SENSOR_TYPES[sensor_type]
|
description = SENSOR_TYPES[sensor_type]
|
||||||
name = f"{info['name']}{description.name or ''}"
|
name_suffix = "" if description.name is UNDEFINED else description.name
|
||||||
|
name = f"{info['name']}{name_suffix}"
|
||||||
if temp_id is not None:
|
if temp_id is not None:
|
||||||
_LOGGER.debug("%s Temp_id: %s", sensor_type, temp_id)
|
_LOGGER.debug("%s Temp_id: %s", sensor_type, temp_id)
|
||||||
name = f"{name}{temp_id}"
|
name = f"{name}{temp_id}"
|
||||||
|
|
|
@ -130,6 +130,7 @@ class RfxtrxBinarySensor(RfxtrxEntity, BinarySensorEntity):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_attr_force_update = True
|
_attr_force_update = True
|
||||||
|
_attr_name = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -275,6 +275,10 @@ def async_setup_entry_rest(
|
||||||
class BlockEntityDescription(EntityDescription):
|
class BlockEntityDescription(EntityDescription):
|
||||||
"""Class to describe a BLOCK entity."""
|
"""Class to describe a BLOCK entity."""
|
||||||
|
|
||||||
|
# BlockEntity does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
icon_fn: Callable[[dict], str] | None = None
|
icon_fn: Callable[[dict], str] | None = None
|
||||||
unit_fn: Callable[[dict], str] | None = None
|
unit_fn: Callable[[dict], str] | None = None
|
||||||
value: Callable[[Any], Any] = lambda val: val
|
value: Callable[[Any], Any] = lambda val: val
|
||||||
|
@ -295,6 +299,10 @@ class RpcEntityRequiredKeysMixin:
|
||||||
class RpcEntityDescription(EntityDescription, RpcEntityRequiredKeysMixin):
|
class RpcEntityDescription(EntityDescription, RpcEntityRequiredKeysMixin):
|
||||||
"""Class to describe a RPC entity."""
|
"""Class to describe a RPC entity."""
|
||||||
|
|
||||||
|
# BlockEntity does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
value: Callable[[Any, Any], Any] | None = None
|
value: Callable[[Any, Any], Any] | None = None
|
||||||
available: Callable[[dict], bool] | None = None
|
available: Callable[[dict], bool] | None = None
|
||||||
removal_condition: Callable[[dict, dict, str], bool] | None = None
|
removal_condition: Callable[[dict, dict, str], bool] | None = None
|
||||||
|
@ -307,6 +315,10 @@ class RpcEntityDescription(EntityDescription, RpcEntityRequiredKeysMixin):
|
||||||
class RestEntityDescription(EntityDescription):
|
class RestEntityDescription(EntityDescription):
|
||||||
"""Class to describe a REST entity."""
|
"""Class to describe a REST entity."""
|
||||||
|
|
||||||
|
# BlockEntity does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
value: Callable[[dict, Any], Any] | None = None
|
value: Callable[[dict, Any], Any] | None = None
|
||||||
extra_state_attributes: Callable[[dict], dict | None] | None = None
|
extra_state_attributes: Callable[[dict], dict | None] | None = None
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,6 @@ class SwitchBotBinarySensor(SwitchbotEntity, BinarySensorEntity):
|
||||||
self._sensor = binary_sensor
|
self._sensor = binary_sensor
|
||||||
self._attr_unique_id = f"{coordinator.base_unique_id}-{binary_sensor}"
|
self._attr_unique_id = f"{coordinator.base_unique_id}-{binary_sensor}"
|
||||||
self.entity_description = BINARY_SENSOR_TYPES[binary_sensor]
|
self.entity_description = BINARY_SENSOR_TYPES[binary_sensor]
|
||||||
self._attr_name = self.entity_description.name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
|
|
|
@ -23,6 +23,10 @@ from .coordinator import SystemBridgeDataUpdateCoordinator
|
||||||
class SystemBridgeBinarySensorEntityDescription(BinarySensorEntityDescription):
|
class SystemBridgeBinarySensorEntityDescription(BinarySensorEntityDescription):
|
||||||
"""Class describing System Bridge binary sensor entities."""
|
"""Class describing System Bridge binary sensor entities."""
|
||||||
|
|
||||||
|
# SystemBridgeBinarySensor does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
value: Callable = round
|
value: Callable = round
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,10 @@ PIXELS: Final = "px"
|
||||||
class SystemBridgeSensorEntityDescription(SensorEntityDescription):
|
class SystemBridgeSensorEntityDescription(SensorEntityDescription):
|
||||||
"""Class describing System Bridge sensor entities."""
|
"""Class describing System Bridge sensor entities."""
|
||||||
|
|
||||||
|
# SystemBridgeSensor does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
value: Callable = round
|
value: Callable = round
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,10 @@ from .const import (
|
||||||
class TomorrowioSensorEntityDescription(SensorEntityDescription):
|
class TomorrowioSensorEntityDescription(SensorEntityDescription):
|
||||||
"""Describes a Tomorrow.io sensor entity."""
|
"""Describes a Tomorrow.io sensor entity."""
|
||||||
|
|
||||||
|
# TomorrowioSensor does not support UNDEFINED or None,
|
||||||
|
# restrict the type to str.
|
||||||
|
name: str = ""
|
||||||
|
|
||||||
unit_imperial: str | None = None
|
unit_imperial: str | None = None
|
||||||
unit_metric: str | None = None
|
unit_metric: str | None = None
|
||||||
multiplication_factor: Callable[[float], float] | float | None = None
|
multiplication_factor: Callable[[float], float] | float | None = None
|
||||||
|
|
|
@ -24,6 +24,7 @@ from homeassistant.const import (
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers import entity_registry as er
|
from homeassistant.helpers import entity_registry as er
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import UNDEFINED
|
||||||
|
|
||||||
from .base_class import TradfriBaseEntity
|
from .base_class import TradfriBaseEntity
|
||||||
from .const import (
|
from .const import (
|
||||||
|
@ -202,7 +203,7 @@ class TradfriSensor(TradfriBaseEntity, SensorEntity):
|
||||||
|
|
||||||
self._attr_unique_id = f"{self._attr_unique_id}-{description.key}"
|
self._attr_unique_id = f"{self._attr_unique_id}-{description.key}"
|
||||||
|
|
||||||
if description.name:
|
if description.name is not UNDEFINED:
|
||||||
self._attr_name = f"{self._attr_name}: {description.name}"
|
self._attr_name = f"{self._attr_name}: {description.name}"
|
||||||
|
|
||||||
self._refresh() # Set initial state
|
self._refresh() # Set initial state
|
||||||
|
|
|
@ -23,6 +23,7 @@ from pyunifiprotect.data import (
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
import homeassistant.helpers.device_registry as dr
|
import homeassistant.helpers.device_registry as dr
|
||||||
from homeassistant.helpers.entity import DeviceInfo, Entity, EntityDescription
|
from homeassistant.helpers.entity import DeviceInfo, Entity, EntityDescription
|
||||||
|
from homeassistant.helpers.typing import UNDEFINED
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_EVENT_ID,
|
ATTR_EVENT_ID,
|
||||||
|
@ -201,7 +202,11 @@ class ProtectDeviceEntity(Entity):
|
||||||
else:
|
else:
|
||||||
self.entity_description = description
|
self.entity_description = description
|
||||||
self._attr_unique_id = f"{self.device.mac}_{description.key}"
|
self._attr_unique_id = f"{self.device.mac}_{description.key}"
|
||||||
name = description.name or ""
|
name = (
|
||||||
|
description.name
|
||||||
|
if description.name and description.name is not UNDEFINED
|
||||||
|
else ""
|
||||||
|
)
|
||||||
self._attr_name = f"{self.device.display_name} {name.title()}"
|
self._attr_name = f"{self.device.display_name} {name.title()}"
|
||||||
if isinstance(description, ProtectRequiredKeysMixin):
|
if isinstance(description, ProtectRequiredKeysMixin):
|
||||||
self._async_get_ufp_enabled = description.get_ufp_enabled
|
self._async_get_ufp_enabled = description.get_ufp_enabled
|
||||||
|
|
|
@ -28,6 +28,9 @@ from .wemo_device import DeviceCoordinator
|
||||||
class AttributeSensorDescription(SensorEntityDescription):
|
class AttributeSensorDescription(SensorEntityDescription):
|
||||||
"""SensorEntityDescription for WeMo AttributeSensor entities."""
|
"""SensorEntityDescription for WeMo AttributeSensor entities."""
|
||||||
|
|
||||||
|
# AttributeSensor does not support UNDEFINED,
|
||||||
|
# restrict the type to str | None.
|
||||||
|
name: str | None = None
|
||||||
state_conversion: Callable[[StateType], StateType] | None = None
|
state_conversion: Callable[[StateType], StateType] | None = None
|
||||||
unique_id_suffix: str | None = None
|
unique_id_suffix: str | None = None
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ from homeassistant.core import callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||||
|
from homeassistant.helpers.typing import UNDEFINED
|
||||||
|
|
||||||
from .const import DOMAIN, LOGGER
|
from .const import DOMAIN, LOGGER
|
||||||
from .discovery import ZwaveDiscoveryInfo
|
from .discovery import ZwaveDiscoveryInfo
|
||||||
|
@ -161,6 +162,7 @@ class ZWaveBaseEntity(Entity):
|
||||||
hasattr(self, "entity_description")
|
hasattr(self, "entity_description")
|
||||||
and self.entity_description
|
and self.entity_description
|
||||||
and self.entity_description.name
|
and self.entity_description.name
|
||||||
|
and self.entity_description.name is not UNDEFINED
|
||||||
):
|
):
|
||||||
name = self.entity_description.name
|
name = self.entity_description.name
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers import entity_platform
|
from homeassistant.helpers import entity_platform
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import UNDEFINED, StateType
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ATTR_METER_TYPE,
|
ATTR_METER_TYPE,
|
||||||
|
@ -610,7 +610,7 @@ class ZwaveSensor(ZWaveBaseEntity, SensorEntity):
|
||||||
|
|
||||||
# Entity class attributes
|
# Entity class attributes
|
||||||
self._attr_force_update = True
|
self._attr_force_update = True
|
||||||
if not entity_description.name:
|
if not entity_description.name or entity_description.name is UNDEFINED:
|
||||||
self._attr_name = self.generate_name(include_value_name=True)
|
self._attr_name = self.generate_name(include_value_name=True)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -44,7 +44,7 @@ from .event import (
|
||||||
async_track_device_registry_updated_event,
|
async_track_device_registry_updated_event,
|
||||||
async_track_entity_registry_updated_event,
|
async_track_entity_registry_updated_event,
|
||||||
)
|
)
|
||||||
from .typing import StateType
|
from .typing import UNDEFINED, StateType, UndefinedType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .entity_platform import EntityPlatform
|
from .entity_platform import EntityPlatform
|
||||||
|
@ -222,7 +222,7 @@ class EntityDescription:
|
||||||
force_update: bool = False
|
force_update: bool = False
|
||||||
icon: str | None = None
|
icon: str | None = None
|
||||||
has_entity_name: bool = False
|
has_entity_name: bool = False
|
||||||
name: str | None = None
|
name: str | UndefinedType | None = UNDEFINED
|
||||||
translation_key: str | None = None
|
translation_key: str | None = None
|
||||||
unit_of_measurement: str | None = None
|
unit_of_measurement: str | None = None
|
||||||
|
|
||||||
|
@ -328,6 +328,22 @@ class Entity(ABC):
|
||||||
return self.entity_description.has_entity_name
|
return self.entity_description.has_entity_name
|
||||||
return False
|
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)
|
||||||
|
|
||||||
|
def _default_to_device_class_name(self) -> bool:
|
||||||
|
"""Return True if an unnamed entity should be named by its device class."""
|
||||||
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str | None:
|
def name(self) -> str | None:
|
||||||
"""Return the name of the entity."""
|
"""Return the name of the entity."""
|
||||||
|
@ -338,11 +354,21 @@ class Entity(ABC):
|
||||||
f"component.{self.platform.platform_name}.entity.{self.platform.domain}"
|
f"component.{self.platform.platform_name}.entity.{self.platform.domain}"
|
||||||
f".{self.translation_key}.name"
|
f".{self.translation_key}.name"
|
||||||
)
|
)
|
||||||
if name_translation_key in self.platform.entity_translations:
|
if name_translation_key in self.platform.platform_translations:
|
||||||
name: str = self.platform.entity_translations[name_translation_key]
|
name: str = self.platform.platform_translations[name_translation_key]
|
||||||
return name
|
return name
|
||||||
if hasattr(self, "entity_description"):
|
if hasattr(self, "entity_description"):
|
||||||
return self.entity_description.name
|
description_name = self.entity_description.name
|
||||||
|
if description_name is UNDEFINED and self._default_to_device_class_name():
|
||||||
|
return self._device_class_name()
|
||||||
|
if description_name is not UNDEFINED:
|
||||||
|
return description_name
|
||||||
|
return None
|
||||||
|
|
||||||
|
# The entity has no name set by _attr_name, translation_key or entity_description
|
||||||
|
# Check if the entity should be named by its device class
|
||||||
|
if self._default_to_device_class_name():
|
||||||
|
return self._device_class_name()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -126,7 +126,8 @@ class EntityPlatform:
|
||||||
self.entity_namespace = entity_namespace
|
self.entity_namespace = entity_namespace
|
||||||
self.config_entry: config_entries.ConfigEntry | None = None
|
self.config_entry: config_entries.ConfigEntry | None = None
|
||||||
self.entities: dict[str, Entity] = {}
|
self.entities: dict[str, Entity] = {}
|
||||||
self.entity_translations: dict[str, Any] = {}
|
self.component_translations: dict[str, Any] = {}
|
||||||
|
self.platform_translations: dict[str, Any] = {}
|
||||||
self._tasks: list[asyncio.Task[None]] = []
|
self._tasks: list[asyncio.Task[None]] = []
|
||||||
# Stop tracking tasks after setup is completed
|
# Stop tracking tasks after setup is completed
|
||||||
self._setup_complete = False
|
self._setup_complete = False
|
||||||
|
@ -295,7 +296,15 @@ class EntityPlatform:
|
||||||
full_name = f"{self.domain}.{self.platform_name}"
|
full_name = f"{self.domain}.{self.platform_name}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.entity_translations = await translation.async_get_translations(
|
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(
|
||||||
hass, hass.config.language, "entity", {self.platform_name}
|
hass, hass.config.language, "entity", {self.platform_name}
|
||||||
)
|
)
|
||||||
except Exception as err: # pylint: disable=broad-exception-caught
|
except Exception as err: # pylint: disable=broad-exception-caught
|
||||||
|
|
|
@ -1,8 +1,25 @@
|
||||||
"""The tests for the Binary sensor component."""
|
"""The tests for the Binary sensor component."""
|
||||||
|
from collections.abc import Generator
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import binary_sensor
|
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
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from tests.common import (
|
||||||
|
MockConfigEntry,
|
||||||
|
MockModule,
|
||||||
|
MockPlatform,
|
||||||
|
mock_config_flow,
|
||||||
|
mock_integration,
|
||||||
|
mock_platform,
|
||||||
|
)
|
||||||
|
|
||||||
|
TEST_DOMAIN = "test"
|
||||||
|
|
||||||
|
|
||||||
def test_state() -> None:
|
def test_state() -> None:
|
||||||
|
@ -19,3 +36,93 @@ def test_state() -> None:
|
||||||
new=True,
|
new=True,
|
||||||
):
|
):
|
||||||
assert binary_sensor.BinarySensorEntity().state == STATE_ON
|
assert binary_sensor.BinarySensorEntity().state == STATE_ON
|
||||||
|
|
||||||
|
|
||||||
|
class STTFlow(ConfigFlow):
|
||||||
|
"""Test flow."""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def config_flow_fixture(hass: HomeAssistant) -> Generator[None, None, None]:
|
||||||
|
"""Mock config flow."""
|
||||||
|
mock_platform(hass, f"{TEST_DOMAIN}.config_flow")
|
||||||
|
|
||||||
|
with mock_config_flow(TEST_DOMAIN, STTFlow):
|
||||||
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
async def test_name(hass: HomeAssistant) -> None:
|
||||||
|
"""Test binary sensor name."""
|
||||||
|
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Unnamed binary sensor without device class -> no name
|
||||||
|
entity1 = binary_sensor.BinarySensorEntity()
|
||||||
|
entity1.entity_id = "binary_sensor.test1"
|
||||||
|
|
||||||
|
# Unnamed binary sensor with device class but has_entity_name False -> no name
|
||||||
|
entity2 = binary_sensor.BinarySensorEntity()
|
||||||
|
entity2.entity_id = "binary_sensor.test2"
|
||||||
|
entity2._attr_device_class = binary_sensor.BinarySensorDeviceClass.BATTERY
|
||||||
|
|
||||||
|
# Unnamed binary sensor with device class and has_entity_name True -> named
|
||||||
|
entity3 = binary_sensor.BinarySensorEntity()
|
||||||
|
entity3.entity_id = "binary_sensor.test3"
|
||||||
|
entity3._attr_device_class = binary_sensor.BinarySensorDeviceClass.BATTERY
|
||||||
|
entity3._attr_has_entity_name = True
|
||||||
|
|
||||||
|
# Unnamed binary sensor with device class and has_entity_name True -> named
|
||||||
|
entity4 = binary_sensor.BinarySensorEntity()
|
||||||
|
entity4.entity_id = "binary_sensor.test4"
|
||||||
|
entity4.entity_description = binary_sensor.BinarySensorEntityDescription(
|
||||||
|
"test",
|
||||||
|
binary_sensor.BinarySensorDeviceClass.BATTERY,
|
||||||
|
has_entity_name=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
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, entity3, entity4])
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
state = hass.states.get(entity1.entity_id)
|
||||||
|
assert state.attributes == {}
|
||||||
|
|
||||||
|
state = hass.states.get(entity2.entity_id)
|
||||||
|
assert state.attributes == {"device_class": "battery"}
|
||||||
|
|
||||||
|
state = hass.states.get(entity3.entity_id)
|
||||||
|
assert state.attributes == {"device_class": "battery", "friendly_name": "Battery"}
|
||||||
|
|
||||||
|
state = hass.states.get(entity4.entity_id)
|
||||||
|
assert state.attributes == {"device_class": "battery", "friendly_name": "Battery"}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue