mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 22:27:07 +00:00
Add additional entities for Shelly BLU TRV (#135244)
* Add valve position sensor * Add valve position and external sensor temperature numbers * Fix method name * Better name * Add remove condition * Add calibration binary sensor * Add battery and signal strength sensors * Remove condition from ShellyRpcEntity * Typo * Add get_entity_class helper * Add tests * Use snapshots in tests
This commit is contained in:
parent
d7ec99de7d
commit
11d44e608b
@ -15,11 +15,12 @@ from homeassistant.components.binary_sensor import (
|
|||||||
)
|
)
|
||||||
from homeassistant.const import STATE_ON, EntityCategory
|
from homeassistant.const import STATE_ON, EntityCategory
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH, DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.restore_state import RestoreEntity
|
from homeassistant.helpers.restore_state import RestoreEntity
|
||||||
|
|
||||||
from .const import CONF_SLEEP_PERIOD
|
from .const import CONF_SLEEP_PERIOD
|
||||||
from .coordinator import ShellyConfigEntry
|
from .coordinator import ShellyConfigEntry, ShellyRpcCoordinator
|
||||||
from .entity import (
|
from .entity import (
|
||||||
BlockEntityDescription,
|
BlockEntityDescription,
|
||||||
RestEntityDescription,
|
RestEntityDescription,
|
||||||
@ -59,6 +60,36 @@ class RestBinarySensorDescription(RestEntityDescription, BinarySensorEntityDescr
|
|||||||
"""Class to describe a REST binary sensor."""
|
"""Class to describe a REST binary sensor."""
|
||||||
|
|
||||||
|
|
||||||
|
class RpcBinarySensor(ShellyRpcAttributeEntity, BinarySensorEntity):
|
||||||
|
"""Represent a RPC binary sensor entity."""
|
||||||
|
|
||||||
|
entity_description: RpcBinarySensorDescription
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool:
|
||||||
|
"""Return true if RPC sensor state is on."""
|
||||||
|
return bool(self.attribute_value)
|
||||||
|
|
||||||
|
|
||||||
|
class RpcBluTrvBinarySensor(RpcBinarySensor):
|
||||||
|
"""Represent a RPC BluTrv binary sensor."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ShellyRpcCoordinator,
|
||||||
|
key: str,
|
||||||
|
attribute: str,
|
||||||
|
description: RpcBinarySensorDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
|
||||||
|
super().__init__(coordinator, key, attribute, description)
|
||||||
|
ble_addr: str = coordinator.device.config[key]["addr"]
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
connections={(CONNECTION_BLUETOOTH, ble_addr)}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
SENSORS: dict[tuple[str, str], BlockBinarySensorDescription] = {
|
SENSORS: dict[tuple[str, str], BlockBinarySensorDescription] = {
|
||||||
("device", "overtemp"): BlockBinarySensorDescription(
|
("device", "overtemp"): BlockBinarySensorDescription(
|
||||||
key="device|overtemp",
|
key="device|overtemp",
|
||||||
@ -232,6 +263,15 @@ RPC_SENSORS: Final = {
|
|||||||
sub_key="value",
|
sub_key="value",
|
||||||
has_entity_name=True,
|
has_entity_name=True,
|
||||||
),
|
),
|
||||||
|
"calibration": RpcBinarySensorDescription(
|
||||||
|
key="blutrv",
|
||||||
|
sub_key="errors",
|
||||||
|
name="Calibration",
|
||||||
|
device_class=BinarySensorDeviceClass.PROBLEM,
|
||||||
|
value=lambda status, _: False if status is None else "not_calibrated" in status,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
entity_class=RpcBluTrvBinarySensor,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -320,17 +360,6 @@ class RestBinarySensor(ShellyRestAttributeEntity, BinarySensorEntity):
|
|||||||
return bool(self.attribute_value)
|
return bool(self.attribute_value)
|
||||||
|
|
||||||
|
|
||||||
class RpcBinarySensor(ShellyRpcAttributeEntity, BinarySensorEntity):
|
|
||||||
"""Represent a RPC binary sensor entity."""
|
|
||||||
|
|
||||||
entity_description: RpcBinarySensorDescription
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self) -> bool:
|
|
||||||
"""Return true if RPC sensor state is on."""
|
|
||||||
return bool(self.attribute_value)
|
|
||||||
|
|
||||||
|
|
||||||
class BlockSleepingBinarySensor(
|
class BlockSleepingBinarySensor(
|
||||||
ShellySleepingBlockAttributeEntity, BinarySensorEntity, RestoreEntity
|
ShellySleepingBlockAttributeEntity, BinarySensorEntity, RestoreEntity
|
||||||
):
|
):
|
||||||
|
@ -196,10 +196,16 @@ def async_setup_rpc_attribute_entities(
|
|||||||
elif description.use_polling_coordinator:
|
elif description.use_polling_coordinator:
|
||||||
if not sleep_period:
|
if not sleep_period:
|
||||||
entities.append(
|
entities.append(
|
||||||
sensor_class(polling_coordinator, key, sensor_id, description)
|
get_entity_class(sensor_class, description)(
|
||||||
|
polling_coordinator, key, sensor_id, description
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
entities.append(sensor_class(coordinator, key, sensor_id, description))
|
entities.append(
|
||||||
|
get_entity_class(sensor_class, description)(
|
||||||
|
coordinator, key, sensor_id, description
|
||||||
|
)
|
||||||
|
)
|
||||||
if not entities:
|
if not entities:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -232,7 +238,9 @@ def async_restore_rpc_attribute_entities(
|
|||||||
|
|
||||||
if description := sensors.get(attribute):
|
if description := sensors.get(attribute):
|
||||||
entities.append(
|
entities.append(
|
||||||
sensor_class(coordinator, key, attribute, description, entry)
|
get_entity_class(sensor_class, description)(
|
||||||
|
coordinator, key, attribute, description, entry
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not entities:
|
if not entities:
|
||||||
@ -293,6 +301,7 @@ class RpcEntityDescription(EntityDescription):
|
|||||||
supported: Callable = lambda _: False
|
supported: Callable = lambda _: False
|
||||||
unit: Callable[[dict], str | None] | None = None
|
unit: Callable[[dict], str | None] | None = None
|
||||||
options_fn: Callable[[dict], list[str]] | None = None
|
options_fn: Callable[[dict], list[str]] | None = None
|
||||||
|
entity_class: Callable | None = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -673,3 +682,13 @@ class ShellySleepingRpcAttributeEntity(ShellyRpcAttributeEntity):
|
|||||||
"Entity %s comes from a sleeping device, update is not possible",
|
"Entity %s comes from a sleeping device, update is not possible",
|
||||||
self.entity_id,
|
self.entity_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_entity_class(
|
||||||
|
sensor_class: Callable, description: RpcEntityDescription
|
||||||
|
) -> Callable:
|
||||||
|
"""Return entity class."""
|
||||||
|
if description.entity_class is not None:
|
||||||
|
return description.entity_class
|
||||||
|
|
||||||
|
return sensor_class
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"number": {
|
"number": {
|
||||||
|
"external_temperature": {
|
||||||
|
"default": "mdi:thermometer-check"
|
||||||
|
},
|
||||||
"valve_position": {
|
"valve_position": {
|
||||||
"default": "mdi:pipe-valve"
|
"default": "mdi:pipe-valve"
|
||||||
}
|
}
|
||||||
@ -29,6 +32,9 @@
|
|||||||
"tilt": {
|
"tilt": {
|
||||||
"default": "mdi:angle-acute"
|
"default": "mdi:angle-acute"
|
||||||
},
|
},
|
||||||
|
"valve_position": {
|
||||||
|
"default": "mdi:pipe-valve"
|
||||||
|
},
|
||||||
"valve_status": {
|
"valve_status": {
|
||||||
"default": "mdi:valve"
|
"default": "mdi:valve"
|
||||||
}
|
}
|
||||||
|
@ -18,9 +18,10 @@ from homeassistant.components.number import (
|
|||||||
NumberMode,
|
NumberMode,
|
||||||
RestoreNumber,
|
RestoreNumber,
|
||||||
)
|
)
|
||||||
from homeassistant.const import PERCENTAGE, EntityCategory
|
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfTemperature
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH, DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.entity_registry import RegistryEntry
|
from homeassistant.helpers.entity_registry import RegistryEntry
|
||||||
|
|
||||||
@ -57,6 +58,74 @@ class RpcNumberDescription(RpcEntityDescription, NumberEntityDescription):
|
|||||||
min_fn: Callable[[dict], float] | None = None
|
min_fn: Callable[[dict], float] | None = None
|
||||||
step_fn: Callable[[dict], float] | None = None
|
step_fn: Callable[[dict], float] | None = None
|
||||||
mode_fn: Callable[[dict], NumberMode] | None = None
|
mode_fn: Callable[[dict], NumberMode] | None = None
|
||||||
|
method: str
|
||||||
|
method_params_fn: Callable[[int, float], dict]
|
||||||
|
|
||||||
|
|
||||||
|
class RpcNumber(ShellyRpcAttributeEntity, NumberEntity):
|
||||||
|
"""Represent a RPC number entity."""
|
||||||
|
|
||||||
|
entity_description: RpcNumberDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ShellyRpcCoordinator,
|
||||||
|
key: str,
|
||||||
|
attribute: str,
|
||||||
|
description: RpcNumberDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize sensor."""
|
||||||
|
super().__init__(coordinator, key, attribute, description)
|
||||||
|
|
||||||
|
if description.max_fn is not None:
|
||||||
|
self._attr_native_max_value = description.max_fn(
|
||||||
|
coordinator.device.config[key]
|
||||||
|
)
|
||||||
|
if description.min_fn is not None:
|
||||||
|
self._attr_native_min_value = description.min_fn(
|
||||||
|
coordinator.device.config[key]
|
||||||
|
)
|
||||||
|
if description.step_fn is not None:
|
||||||
|
self._attr_native_step = description.step_fn(coordinator.device.config[key])
|
||||||
|
if description.mode_fn is not None:
|
||||||
|
self._attr_mode = description.mode_fn(coordinator.device.config[key])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> float | None:
|
||||||
|
"""Return value of number."""
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
assert isinstance(self.attribute_value, float | None)
|
||||||
|
|
||||||
|
return self.attribute_value
|
||||||
|
|
||||||
|
async def async_set_native_value(self, value: float) -> None:
|
||||||
|
"""Change the value."""
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
assert isinstance(self._id, int)
|
||||||
|
|
||||||
|
await self.call_rpc(
|
||||||
|
self.entity_description.method,
|
||||||
|
self.entity_description.method_params_fn(self._id, value),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RpcBluTrvNumber(RpcNumber):
|
||||||
|
"""Represent a RPC BluTrv number."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ShellyRpcCoordinator,
|
||||||
|
key: str,
|
||||||
|
attribute: str,
|
||||||
|
description: RpcNumberDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
|
||||||
|
super().__init__(coordinator, key, attribute, description)
|
||||||
|
ble_addr: str = coordinator.device.config[key]["addr"]
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
connections={(CONNECTION_BLUETOOTH, ble_addr)}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
NUMBERS: dict[tuple[str, str], BlockNumberDescription] = {
|
NUMBERS: dict[tuple[str, str], BlockNumberDescription] = {
|
||||||
@ -78,6 +147,25 @@ NUMBERS: dict[tuple[str, str], BlockNumberDescription] = {
|
|||||||
|
|
||||||
|
|
||||||
RPC_NUMBERS: Final = {
|
RPC_NUMBERS: Final = {
|
||||||
|
"external_temperature": RpcNumberDescription(
|
||||||
|
key="blutrv",
|
||||||
|
sub_key="current_C",
|
||||||
|
translation_key="external_temperature",
|
||||||
|
name="External temperature",
|
||||||
|
native_min_value=-50,
|
||||||
|
native_max_value=50,
|
||||||
|
native_step=0.1,
|
||||||
|
mode=NumberMode.BOX,
|
||||||
|
entity_category=EntityCategory.CONFIG,
|
||||||
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||||
|
method="BluTRV.Call",
|
||||||
|
method_params_fn=lambda idx, value: {
|
||||||
|
"id": idx,
|
||||||
|
"method": "Trv.SetExternalTemperature",
|
||||||
|
"params": {"id": 0, "t_C": value},
|
||||||
|
},
|
||||||
|
entity_class=RpcBluTrvNumber,
|
||||||
|
),
|
||||||
"number": RpcNumberDescription(
|
"number": RpcNumberDescription(
|
||||||
key="number",
|
key="number",
|
||||||
sub_key="value",
|
sub_key="value",
|
||||||
@ -92,6 +180,28 @@ RPC_NUMBERS: 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,
|
||||||
|
method="Number.Set",
|
||||||
|
method_params_fn=lambda idx, value: {"id": idx, "value": value},
|
||||||
|
),
|
||||||
|
"valve_position": RpcNumberDescription(
|
||||||
|
key="blutrv",
|
||||||
|
sub_key="pos",
|
||||||
|
translation_key="valve_position",
|
||||||
|
name="Valve position",
|
||||||
|
native_min_value=0,
|
||||||
|
native_max_value=100,
|
||||||
|
native_step=1,
|
||||||
|
mode=NumberMode.SLIDER,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
method="BluTRV.Call",
|
||||||
|
method_params_fn=lambda idx, value: {
|
||||||
|
"id": idx,
|
||||||
|
"method": "Trv.SetPosition",
|
||||||
|
"params": {"id": 0, "pos": value},
|
||||||
|
},
|
||||||
|
removal_condition=lambda config, _status, key: config[key].get("enable", True)
|
||||||
|
is True,
|
||||||
|
entity_class=RpcBluTrvNumber,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,44 +300,3 @@ class BlockSleepingNumber(ShellySleepingBlockAttributeEntity, RestoreNumber):
|
|||||||
) from err
|
) from err
|
||||||
except InvalidAuthError:
|
except InvalidAuthError:
|
||||||
await self.coordinator.async_shutdown_device_and_start_reauth()
|
await self.coordinator.async_shutdown_device_and_start_reauth()
|
||||||
|
|
||||||
|
|
||||||
class RpcNumber(ShellyRpcAttributeEntity, NumberEntity):
|
|
||||||
"""Represent a RPC number entity."""
|
|
||||||
|
|
||||||
entity_description: RpcNumberDescription
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
coordinator: ShellyRpcCoordinator,
|
|
||||||
key: str,
|
|
||||||
attribute: str,
|
|
||||||
description: RpcNumberDescription,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize sensor."""
|
|
||||||
super().__init__(coordinator, key, attribute, description)
|
|
||||||
|
|
||||||
if description.max_fn is not None:
|
|
||||||
self._attr_native_max_value = description.max_fn(
|
|
||||||
coordinator.device.config[key]
|
|
||||||
)
|
|
||||||
if description.min_fn is not None:
|
|
||||||
self._attr_native_min_value = description.min_fn(
|
|
||||||
coordinator.device.config[key]
|
|
||||||
)
|
|
||||||
if description.step_fn is not None:
|
|
||||||
self._attr_native_step = description.step_fn(coordinator.device.config[key])
|
|
||||||
if description.mode_fn is not None:
|
|
||||||
self._attr_mode = description.mode_fn(coordinator.device.config[key])
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self) -> float | None:
|
|
||||||
"""Return value of number."""
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
assert isinstance(self.attribute_value, float | None)
|
|
||||||
|
|
||||||
return self.attribute_value
|
|
||||||
|
|
||||||
async def async_set_native_value(self, value: float) -> None:
|
|
||||||
"""Change the value."""
|
|
||||||
await self.call_rpc("Number.Set", {"id": self._id, "value": value})
|
|
||||||
|
@ -33,6 +33,7 @@ from homeassistant.const import (
|
|||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.device_registry import CONNECTION_BLUETOOTH, DeviceInfo
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
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
|
||||||
@ -76,6 +77,57 @@ class RestSensorDescription(RestEntityDescription, SensorEntityDescription):
|
|||||||
"""Class to describe a REST sensor."""
|
"""Class to describe a REST sensor."""
|
||||||
|
|
||||||
|
|
||||||
|
class RpcSensor(ShellyRpcAttributeEntity, SensorEntity):
|
||||||
|
"""Represent a RPC sensor."""
|
||||||
|
|
||||||
|
entity_description: RpcSensorDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ShellyRpcCoordinator,
|
||||||
|
key: str,
|
||||||
|
attribute: str,
|
||||||
|
description: RpcSensorDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize select."""
|
||||||
|
super().__init__(coordinator, key, attribute, description)
|
||||||
|
|
||||||
|
if self.option_map:
|
||||||
|
self._attr_options = list(self.option_map.values())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def native_value(self) -> StateType:
|
||||||
|
"""Return value of sensor."""
|
||||||
|
attribute_value = self.attribute_value
|
||||||
|
|
||||||
|
if not self.option_map:
|
||||||
|
return attribute_value
|
||||||
|
|
||||||
|
if not isinstance(attribute_value, str):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.option_map[attribute_value]
|
||||||
|
|
||||||
|
|
||||||
|
class RpcBluTrvSensor(RpcSensor):
|
||||||
|
"""Represent a RPC BluTrv sensor."""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: ShellyRpcCoordinator,
|
||||||
|
key: str,
|
||||||
|
attribute: str,
|
||||||
|
description: RpcSensorDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize."""
|
||||||
|
|
||||||
|
super().__init__(coordinator, key, attribute, description)
|
||||||
|
ble_addr: str = coordinator.device.config[key]["addr"]
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
connections={(CONNECTION_BLUETOOTH, ble_addr)}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
SENSORS: dict[tuple[str, str], BlockSensorDescription] = {
|
SENSORS: dict[tuple[str, str], BlockSensorDescription] = {
|
||||||
("device", "battery"): BlockSensorDescription(
|
("device", "battery"): BlockSensorDescription(
|
||||||
key="device|battery",
|
key="device|battery",
|
||||||
@ -1222,6 +1274,38 @@ RPC_SENSORS: Final = {
|
|||||||
options_fn=lambda config: config["options"],
|
options_fn=lambda config: config["options"],
|
||||||
device_class=SensorDeviceClass.ENUM,
|
device_class=SensorDeviceClass.ENUM,
|
||||||
),
|
),
|
||||||
|
"valve_position": RpcSensorDescription(
|
||||||
|
key="blutrv",
|
||||||
|
sub_key="pos",
|
||||||
|
name="Valve position",
|
||||||
|
translation_key="valve_position",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
removal_condition=lambda config, _status, key: config[key].get("enable", False)
|
||||||
|
is False,
|
||||||
|
entity_class=RpcBluTrvSensor,
|
||||||
|
),
|
||||||
|
"blutrv_battery": RpcSensorDescription(
|
||||||
|
key="blutrv",
|
||||||
|
sub_key="battery",
|
||||||
|
name="Battery",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
device_class=SensorDeviceClass.BATTERY,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
entity_class=RpcBluTrvSensor,
|
||||||
|
),
|
||||||
|
"blutrv_rssi": RpcSensorDescription(
|
||||||
|
key="blutrv",
|
||||||
|
sub_key="rssi",
|
||||||
|
name="Signal strength",
|
||||||
|
native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||||
|
device_class=SensorDeviceClass.SIGNAL_STRENGTH,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
entity_class=RpcBluTrvSensor,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1327,38 +1411,6 @@ class RestSensor(ShellyRestAttributeEntity, SensorEntity):
|
|||||||
return self.attribute_value
|
return self.attribute_value
|
||||||
|
|
||||||
|
|
||||||
class RpcSensor(ShellyRpcAttributeEntity, SensorEntity):
|
|
||||||
"""Represent a RPC sensor."""
|
|
||||||
|
|
||||||
entity_description: RpcSensorDescription
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
coordinator: ShellyRpcCoordinator,
|
|
||||||
key: str,
|
|
||||||
attribute: str,
|
|
||||||
description: RpcSensorDescription,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize select."""
|
|
||||||
super().__init__(coordinator, key, attribute, description)
|
|
||||||
|
|
||||||
if self.option_map:
|
|
||||||
self._attr_options = list(self.option_map.values())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self) -> StateType:
|
|
||||||
"""Return value of sensor."""
|
|
||||||
attribute_value = self.attribute_value
|
|
||||||
|
|
||||||
if not self.option_map:
|
|
||||||
return attribute_value
|
|
||||||
|
|
||||||
if not isinstance(attribute_value, str):
|
|
||||||
return None
|
|
||||||
|
|
||||||
return self.option_map[attribute_value]
|
|
||||||
|
|
||||||
|
|
||||||
class BlockSleepingSensor(ShellySleepingBlockAttributeEntity, RestoreSensor):
|
class BlockSleepingSensor(ShellySleepingBlockAttributeEntity, RestoreSensor):
|
||||||
"""Represent a block sleeping sensor."""
|
"""Represent a block sleeping sensor."""
|
||||||
|
|
||||||
|
@ -255,6 +255,8 @@ MOCK_BLU_TRV_REMOTE_STATUS = {
|
|||||||
"current_C": 15.2,
|
"current_C": 15.2,
|
||||||
"target_C": 17.1,
|
"target_C": 17.1,
|
||||||
"schedule_rev": 0,
|
"schedule_rev": 0,
|
||||||
|
"rssi": -60,
|
||||||
|
"battery": 100,
|
||||||
"errors": [],
|
"errors": [],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
48
tests/components/shelly/snapshots/test_binary_sensor.ambr
Normal file
48
tests/components/shelly/snapshots/test_binary_sensor.ambr
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_blu_trv_binary_sensor_entity[binary_sensor.trv_name_calibration-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': None,
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'binary_sensor',
|
||||||
|
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||||
|
'entity_id': 'binary_sensor.trv_name_calibration',
|
||||||
|
'has_entity_name': False,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <BinarySensorDeviceClass.PROBLEM: 'problem'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'TRV-Name calibration',
|
||||||
|
'platform': 'shelly',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': '123456789ABC-blutrv:200-calibration',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_binary_sensor_entity[binary_sensor.trv_name_calibration-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'problem',
|
||||||
|
'friendly_name': 'TRV-Name calibration',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'binary_sensor.trv_name_calibration',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'off',
|
||||||
|
})
|
||||||
|
# ---
|
113
tests/components/shelly/snapshots/test_number.ambr
Normal file
113
tests/components/shelly/snapshots/test_number.ambr
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_blu_trv_number_entity[number.trv_name_external_temperature-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'max': 50,
|
||||||
|
'min': -50,
|
||||||
|
'mode': <NumberMode.BOX: 'box'>,
|
||||||
|
'step': 0.1,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'number',
|
||||||
|
'entity_category': <EntityCategory.CONFIG: 'config'>,
|
||||||
|
'entity_id': 'number.trv_name_external_temperature',
|
||||||
|
'has_entity_name': False,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'TRV-Name external temperature',
|
||||||
|
'platform': 'shelly',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'external_temperature',
|
||||||
|
'unique_id': '123456789ABC-blutrv:200-external_temperature',
|
||||||
|
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_number_entity[number.trv_name_external_temperature-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'TRV-Name external temperature',
|
||||||
|
'max': 50,
|
||||||
|
'min': -50,
|
||||||
|
'mode': <NumberMode.BOX: 'box'>,
|
||||||
|
'step': 0.1,
|
||||||
|
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'number.trv_name_external_temperature',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '15.2',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_number_entity[number.trv_name_valve_position-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'max': 100,
|
||||||
|
'min': 0,
|
||||||
|
'mode': <NumberMode.SLIDER: 'slider'>,
|
||||||
|
'step': 1,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'number',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'number.trv_name_valve_position',
|
||||||
|
'has_entity_name': False,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'TRV-Name valve position',
|
||||||
|
'platform': 'shelly',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'valve_position',
|
||||||
|
'unique_id': '123456789ABC-blutrv:200-valve_position',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_number_entity[number.trv_name_valve_position-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'TRV-Name valve position',
|
||||||
|
'max': 100,
|
||||||
|
'min': 0,
|
||||||
|
'mode': <NumberMode.SLIDER: 'slider'>,
|
||||||
|
'step': 1,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'number.trv_name_valve_position',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '0',
|
||||||
|
})
|
||||||
|
# ---
|
153
tests/components/shelly/snapshots/test_sensor.ambr
Normal file
153
tests/components/shelly/snapshots/test_sensor.ambr
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_blu_trv_sensor_entity[sensor.trv_name_battery-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||||
|
'entity_id': 'sensor.trv_name_battery',
|
||||||
|
'has_entity_name': False,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.BATTERY: 'battery'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'TRV-Name battery',
|
||||||
|
'platform': 'shelly',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': '123456789ABC-blutrv:200-blutrv_battery',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_sensor_entity[sensor.trv_name_battery-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'battery',
|
||||||
|
'friendly_name': 'TRV-Name battery',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.trv_name_battery',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '100',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_sensor_entity[sensor.trv_name_signal_strength-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||||
|
'entity_id': 'sensor.trv_name_signal_strength',
|
||||||
|
'has_entity_name': False,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'TRV-Name signal strength',
|
||||||
|
'platform': 'shelly',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': '123456789ABC-blutrv:200-blutrv_rssi',
|
||||||
|
'unit_of_measurement': 'dBm',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_sensor_entity[sensor.trv_name_signal_strength-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'signal_strength',
|
||||||
|
'friendly_name': 'TRV-Name signal strength',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': 'dBm',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.trv_name_signal_strength',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '-60',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_sensor_entity[sensor.trv_name_valve_position-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||||
|
'entity_id': 'sensor.trv_name_valve_position',
|
||||||
|
'has_entity_name': False,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'TRV-Name valve position',
|
||||||
|
'platform': 'shelly',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': 'valve_position',
|
||||||
|
'unique_id': '123456789ABC-blutrv:200-valve_position',
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_blu_trv_sensor_entity[sensor.trv_name_valve_position-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'TRV-Name valve position',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': '%',
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.trv_name_valve_position',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '0',
|
||||||
|
})
|
||||||
|
# ---
|
@ -3,9 +3,10 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
from aioshelly.const import MODEL_MOTION
|
from aioshelly.const import MODEL_BLU_GATEWAY_GEN3, MODEL_MOTION
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
import pytest
|
import pytest
|
||||||
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
|
||||||
from homeassistant.components.shelly.const import UPDATE_PERIOD_MULTIPLIER
|
from homeassistant.components.shelly.const import UPDATE_PERIOD_MULTIPLIER
|
||||||
@ -477,3 +478,22 @@ async def test_rpc_remove_virtual_binary_sensor_when_orphaned(
|
|||||||
|
|
||||||
entry = entity_registry.async_get(entity_id)
|
entry = entity_registry.async_get(entity_id)
|
||||||
assert not entry
|
assert not entry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_blu_trv_binary_sensor_entity(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_blu_trv: Mock,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test BLU TRV binary sensor entity."""
|
||||||
|
await init_integration(hass, 3, model=MODEL_BLU_GATEWAY_GEN3)
|
||||||
|
|
||||||
|
for entity in ("calibration",):
|
||||||
|
entity_id = f"{BINARY_SENSOR_DOMAIN}.trv_name_{entity}"
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state == snapshot(name=f"{entity_id}-state")
|
||||||
|
|
||||||
|
entry = entity_registry.async_get(entity_id)
|
||||||
|
assert entry == snapshot(name=f"{entity_id}-entry")
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from unittest.mock import AsyncMock, Mock
|
from unittest.mock import AsyncMock, Mock
|
||||||
|
|
||||||
|
from aioshelly.const import MODEL_BLU_GATEWAY_GEN3
|
||||||
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError
|
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError
|
||||||
import pytest
|
import pytest
|
||||||
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
from homeassistant.components.number import (
|
from homeassistant.components.number import (
|
||||||
ATTR_MAX,
|
ATTR_MAX,
|
||||||
@ -390,3 +392,26 @@ async def test_rpc_remove_virtual_number_when_orphaned(
|
|||||||
|
|
||||||
entry = entity_registry.async_get(entity_id)
|
entry = entity_registry.async_get(entity_id)
|
||||||
assert not entry
|
assert not entry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_blu_trv_number_entity(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_blu_trv: Mock,
|
||||||
|
entity_registry: EntityRegistry,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test BLU TRV number entity."""
|
||||||
|
# disable automatic temperature control in the device
|
||||||
|
monkeypatch.setitem(mock_blu_trv.config["blutrv:200"], "enable", False)
|
||||||
|
|
||||||
|
await init_integration(hass, 3, model=MODEL_BLU_GATEWAY_GEN3)
|
||||||
|
|
||||||
|
for entity in ("external_temperature", "valve_position"):
|
||||||
|
entity_id = f"{NUMBER_DOMAIN}.trv_name_{entity}"
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state == snapshot(name=f"{entity_id}-state")
|
||||||
|
|
||||||
|
entry = entity_registry.async_get(entity_id)
|
||||||
|
assert entry == snapshot(name=f"{entity_id}-entry")
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
from aioshelly.const import MODEL_BLU_GATEWAY_GEN3
|
||||||
from freezegun.api import FrozenDateTimeFactory
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
import pytest
|
import pytest
|
||||||
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
from homeassistant.components.homeassistant import (
|
from homeassistant.components.homeassistant import (
|
||||||
DOMAIN as HA_DOMAIN,
|
DOMAIN as HA_DOMAIN,
|
||||||
@ -1405,3 +1407,22 @@ async def test_rpc_voltmeter_value(
|
|||||||
entry = entity_registry.async_get(entity_id)
|
entry = entity_registry.async_get(entity_id)
|
||||||
assert entry
|
assert entry
|
||||||
assert entry.unique_id == "123456789ABC-voltmeter:100-voltmeter_value"
|
assert entry.unique_id == "123456789ABC-voltmeter:100-voltmeter_value"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_blu_trv_sensor_entity(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_blu_trv: Mock,
|
||||||
|
entity_registry: EntityRegistry,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test BLU TRV sensor entity."""
|
||||||
|
await init_integration(hass, 3, model=MODEL_BLU_GATEWAY_GEN3)
|
||||||
|
|
||||||
|
for entity in ("battery", "signal_strength", "valve_position"):
|
||||||
|
entity_id = f"{SENSOR_DOMAIN}.trv_name_{entity}"
|
||||||
|
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state == snapshot(name=f"{entity_id}-state")
|
||||||
|
|
||||||
|
entry = entity_registry.async_get(entity_id)
|
||||||
|
assert entry == snapshot(name=f"{entity_id}-entry")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user