mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 07:07:28 +00:00
Set the device class for the Shelly virtual sensor (#137068)
* Map sensor role to the device class * Add test * Fix docstring
This commit is contained in:
parent
b3205ea1cd
commit
6ff733b225
@ -28,6 +28,7 @@ from aioshelly.const import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components.number import NumberMode
|
from homeassistant.components.number import NumberMode
|
||||||
|
from homeassistant.components.sensor import SensorDeviceClass
|
||||||
|
|
||||||
DOMAIN: Final = "shelly"
|
DOMAIN: Final = "shelly"
|
||||||
|
|
||||||
@ -272,3 +273,8 @@ COMPONENT_ID_PATTERN = re.compile(r"[a-z\d]+:\d+")
|
|||||||
|
|
||||||
# value confirmed by Shelly team
|
# value confirmed by Shelly team
|
||||||
BLU_TRV_TIMEOUT = 60
|
BLU_TRV_TIMEOUT = 60
|
||||||
|
|
||||||
|
ROLE_TO_DEVICE_CLASS_MAP = {
|
||||||
|
"current_humidity": SensorDeviceClass.HUMIDITY,
|
||||||
|
"current_temperature": SensorDeviceClass.TEMPERATURE,
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Final, cast
|
from typing import Final, cast
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||||||
from homeassistant.helpers.entity_registry import RegistryEntry
|
from homeassistant.helpers.entity_registry import RegistryEntry
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
|
|
||||||
from .const import CONF_SLEEP_PERIOD, SHAIR_MAX_WORK_HOURS
|
from .const import CONF_SLEEP_PERIOD, ROLE_TO_DEVICE_CLASS_MAP, SHAIR_MAX_WORK_HOURS
|
||||||
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
|
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
|
||||||
from .entity import (
|
from .entity import (
|
||||||
BlockEntityDescription,
|
BlockEntityDescription,
|
||||||
@ -71,6 +72,8 @@ class BlockSensorDescription(BlockEntityDescription, SensorEntityDescription):
|
|||||||
class RpcSensorDescription(RpcEntityDescription, SensorEntityDescription):
|
class RpcSensorDescription(RpcEntityDescription, SensorEntityDescription):
|
||||||
"""Class to describe a RPC sensor."""
|
"""Class to describe a RPC sensor."""
|
||||||
|
|
||||||
|
device_class_fn: Callable[[dict], SensorDeviceClass | None] | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True, kw_only=True)
|
@dataclass(frozen=True, kw_only=True)
|
||||||
class RestSensorDescription(RestEntityDescription, SensorEntityDescription):
|
class RestSensorDescription(RestEntityDescription, SensorEntityDescription):
|
||||||
@ -95,6 +98,12 @@ class RpcSensor(ShellyRpcAttributeEntity, SensorEntity):
|
|||||||
if self.option_map:
|
if self.option_map:
|
||||||
self._attr_options = list(self.option_map.values())
|
self._attr_options = list(self.option_map.values())
|
||||||
|
|
||||||
|
if description.device_class_fn is not None:
|
||||||
|
if device_class := description.device_class_fn(
|
||||||
|
coordinator.device.config[key]
|
||||||
|
):
|
||||||
|
self._attr_device_class = device_class
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> StateType:
|
def native_value(self) -> StateType:
|
||||||
"""Return value of sensor."""
|
"""Return value of sensor."""
|
||||||
@ -1266,6 +1275,9 @@ RPC_SENSORS: Final = {
|
|||||||
unit=lambda config: config["meta"]["ui"]["unit"]
|
unit=lambda config: config["meta"]["ui"]["unit"]
|
||||||
if config["meta"]["ui"]["unit"]
|
if config["meta"]["ui"]["unit"]
|
||||||
else None,
|
else None,
|
||||||
|
device_class_fn=lambda config: ROLE_TO_DEVICE_CLASS_MAP.get(config["role"])
|
||||||
|
if "role" in config
|
||||||
|
else None,
|
||||||
),
|
),
|
||||||
"enum": RpcSensorDescription(
|
"enum": RpcSensorDescription(
|
||||||
key="enum",
|
key="enum",
|
||||||
|
@ -1426,3 +1426,32 @@ async def test_blu_trv_sensor_entity(
|
|||||||
|
|
||||||
entry = entity_registry.async_get(entity_id)
|
entry = entity_registry.async_get(entity_id)
|
||||||
assert entry == snapshot(name=f"{entity_id}-entry")
|
assert entry == snapshot(name=f"{entity_id}-entry")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rpc_device_virtual_number_sensor_with_device_class(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_rpc_device: Mock,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
) -> None:
|
||||||
|
"""Test a virtual number sensor with device class for RPC device."""
|
||||||
|
config = deepcopy(mock_rpc_device.config)
|
||||||
|
config["number:203"] = {
|
||||||
|
"name": "Current humidity",
|
||||||
|
"min": 0,
|
||||||
|
"max": 100,
|
||||||
|
"meta": {"ui": {"step": 1, "unit": "%", "view": "label"}},
|
||||||
|
"role": "current_humidity",
|
||||||
|
}
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "config", config)
|
||||||
|
|
||||||
|
status = deepcopy(mock_rpc_device.status)
|
||||||
|
status["number:203"] = {"value": 34}
|
||||||
|
monkeypatch.setattr(mock_rpc_device, "status", status)
|
||||||
|
|
||||||
|
await init_integration(hass, 3)
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.test_name_current_humidity")
|
||||||
|
assert state
|
||||||
|
assert state.state == "34"
|
||||||
|
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE
|
||||||
|
assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.HUMIDITY
|
||||||
|
Loading…
x
Reference in New Issue
Block a user