WolfllinkSensorEntityDescriptions and updated tests

This commit is contained in:
EnjoyingM
2025-02-25 23:51:12 +00:00
parent a0485e03bf
commit 7074980e18
2 changed files with 175 additions and 68 deletions

View File

@@ -2,6 +2,9 @@
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from wolf_comm.models import (
EnergyParameter,
HoursParameter,
@@ -10,6 +13,7 @@ from wolf_comm.models import (
PercentageParameter,
PowerParameter,
Pressure,
SimpleParameter,
Temperature,
)
@@ -55,70 +59,95 @@ async def async_setup_entry(
async_add_entities(entities, True)
def get_entity_description(parameter: Parameter) -> SensorEntityDescription:
@dataclass(kw_only=True, frozen=True)
class WolflinkSensorEntityDescription(SensorEntityDescription):
"""Describes Wolflink sensor entity."""
supported_fn: Callable[[Parameter], bool]
SENSOR_DESCRIPTIONS = [
WolflinkSensorEntityDescription(
key="temperature",
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
supported_fn=lambda param: isinstance(param, Temperature),
),
WolflinkSensorEntityDescription(
key="pressure",
device_class=SensorDeviceClass.PRESSURE,
native_unit_of_measurement=UnitOfPressure.BAR,
supported_fn=lambda param: isinstance(param, Pressure),
),
WolflinkSensorEntityDescription(
key="energy",
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
supported_fn=lambda param: isinstance(param, EnergyParameter),
),
WolflinkSensorEntityDescription(
key="power",
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
supported_fn=lambda param: isinstance(param, PowerParameter),
),
WolflinkSensorEntityDescription(
key="percentage",
native_unit_of_measurement=PERCENTAGE,
supported_fn=lambda param: isinstance(param, PercentageParameter),
),
WolflinkSensorEntityDescription(
key="list_item",
translation_key="state",
supported_fn=lambda param: isinstance(param, ListItemParameter),
),
WolflinkSensorEntityDescription(
key="hours",
icon="mdi:clock",
native_unit_of_measurement=UnitOfTime.HOURS,
supported_fn=lambda param: isinstance(param, HoursParameter),
),
WolflinkSensorEntityDescription(
key="default",
supported_fn=lambda param: isinstance(param, SimpleParameter),
),
]
def get_entity_description(parameter: Parameter) -> WolflinkSensorEntityDescription:
"""Return the entity description for a given parameter."""
if isinstance(parameter, Temperature):
return SensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
device_class=SensorDeviceClass.TEMPERATURE,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
)
if isinstance(parameter, Pressure):
return SensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
device_class=SensorDeviceClass.PRESSURE,
native_unit_of_measurement=UnitOfPressure.BAR,
)
if isinstance(parameter, EnergyParameter):
return SensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
device_class=SensorDeviceClass.ENERGY,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
)
if isinstance(parameter, PowerParameter):
return SensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
device_class=SensorDeviceClass.POWER,
native_unit_of_measurement=UnitOfPower.KILO_WATT,
)
if isinstance(parameter, PercentageParameter):
return SensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
native_unit_of_measurement=PERCENTAGE,
)
if isinstance(parameter, ListItemParameter):
return SensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
translation_key="state",
)
if isinstance(parameter, HoursParameter):
return SensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
icon="mdi:clock",
native_unit_of_measurement=UnitOfTime.HOURS,
)
return SensorEntityDescription(
for description in SENSOR_DESCRIPTIONS:
if description.supported_fn(parameter):
return WolflinkSensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
device_class=description.device_class,
native_unit_of_measurement=description.native_unit_of_measurement,
icon=description.icon,
entity_registry_enabled_default=description.entity_registry_enabled_default,
entity_category=description.entity_category,
has_entity_name=description.has_entity_name,
translation_key=description.translation_key,
supported_fn=description.supported_fn,
)
return WolflinkSensorEntityDescription(
key=parameter.parameter_id,
name=parameter.name,
supported_fn=lambda param: True,
)
class WolfLinkSensor(CoordinatorEntity, SensorEntity):
"""Base class for all Wolf entities."""
entity_description: WolflinkSensorEntityDescription
def __init__(
self,
coordinator,
wolf_object: Parameter,
device_id: str,
description: SensorEntityDescription,
description: WolflinkSensorEntityDescription,
) -> None:
"""Initialize."""
super().__init__(coordinator)
@@ -162,10 +191,3 @@ class WolfLinkSensor(CoordinatorEntity, SensorEntity):
"value_id": self.wolf_object.value_id,
"parent": self.wolf_object.parent,
}
@property
def native_unit_of_measurement(self) -> str | None:
"""Return the unit the value is expressed in."""
if isinstance(self.wolf_object, PercentageParameter):
return self.wolf_object.unit
return self.entity_description.native_unit_of_measurement

View File

@@ -1,16 +1,18 @@
"""Test the Wolf SmartSet Service Sensor platform."""
from unittest.mock import MagicMock
from unittest.mock import MagicMock, Mock
import pytest
from wolf_comm import (
PERCENTAGE,
EnergyParameter,
HoursParameter,
ListItemParameter,
Parameter,
PercentageParameter,
PowerParameter,
Pressure,
SimpleParameter,
Temperature,
)
@@ -21,7 +23,11 @@ from homeassistant.components.wolflink.const import (
MANUFACTURER,
PARAMETERS,
)
from homeassistant.components.wolflink.sensor import WolfLinkSensor, async_setup_entry
from homeassistant.components.wolflink.sensor import (
WolfLinkSensor,
async_setup_entry,
get_entity_description,
)
from homeassistant.const import (
UnitOfEnergy,
UnitOfPower,
@@ -34,7 +40,7 @@ from homeassistant.helpers import device_registry as dr
from .const import CONFIG
from tests.common import MockConfigEntry
from tests.common import Literal, MockConfigEntry
@pytest.fixture
@@ -46,6 +52,18 @@ def mock_coordinator(hass: HomeAssistant) -> MagicMock:
return coordinator
@pytest.fixture
def mock_device_id():
"""Fixture for a mock device ID."""
return "1234"
@pytest.fixture
def mock_parameter():
"""Fixture for a mock parameter."""
return Mock(spec=Parameter)
async def mock_config_entry(
hass: HomeAssistant, device_registry: dr.DeviceRegistry
) -> None:
@@ -55,13 +73,9 @@ async def mock_config_entry(
)
config_entry.add_to_hass(hass)
device_id = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
identifiers={(DOMAIN, CONFIG[DEVICE_ID])},
configuration_url="https://www.wolf-smartset.com/",
manufacturer=MANUFACTURER,
).id
assert device_registry.async_get(device_id).identifiers == {(DOMAIN, "1234")}
device = device_registry.async_get_device({(DOMAIN, CONFIG[DEVICE_ID])})
assert device is not None
assert device.identifiers == {(DOMAIN, CONFIG[DEVICE_ID])}
def test_wolflink_sensor_native_value(mock_coordinator: MagicMock) -> None:
@@ -117,7 +131,7 @@ async def test_async_setup_entry(
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = {
PARAMETERS: [parameter],
COORDINATOR: mock_coordinator,
DEVICE_ID: "mock_device_id",
DEVICE_ID: "1234",
}
async_add_entities = MagicMock()
@@ -129,3 +143,74 @@ async def test_async_setup_entry(
entity = entities[0]
assert isinstance(entity, expected_class)
assert entity.native_unit_of_measurement == expected_unit
def test_get_entity_description() -> None:
"""Test the get_entity_description function."""
parameter = Mock(spec=Temperature)
description = get_entity_description(parameter)
assert description.device_class == "temperature"
assert description.native_unit_of_measurement == "°C"
parameter = Mock(spec=Pressure)
description = get_entity_description(parameter)
assert description.device_class == "pressure"
assert description.native_unit_of_measurement == "bar"
parameter = Mock(spec=EnergyParameter)
description = get_entity_description(parameter)
assert description.device_class == "energy"
assert description.native_unit_of_measurement == "kWh"
parameter = Mock(spec=PowerParameter)
description = get_entity_description(parameter)
assert description.device_class == "power"
assert description.native_unit_of_measurement == "kW"
parameter = Mock(spec=PercentageParameter)
description = get_entity_description(parameter)
assert description.native_unit_of_measurement == PERCENTAGE
parameter = Mock(spec=ListItemParameter)
description = get_entity_description(parameter)
assert description.translation_key == "state"
parameter = Mock(spec=HoursParameter)
description = get_entity_description(parameter)
assert description.native_unit_of_measurement == UnitOfTime.HOURS
assert description.icon == "mdi:clock"
parameter = Mock(spec=SimpleParameter)
description = get_entity_description(parameter)
def test_wolflink_sensor(
mock_coordinator, mock_device_id: Literal["1234"], mock_parameter
) -> None:
"""Test the WolfLinkSensor class."""
description = get_entity_description(mock_parameter)
sensor = WolfLinkSensor(
mock_coordinator, mock_parameter, mock_device_id, description
)
assert sensor.entity_description == description
assert sensor.wolf_object == mock_parameter
assert sensor._attr_name == description.name
assert sensor._attr_unique_id == f"{mock_device_id}:{mock_parameter.parameter_id}"
assert sensor._attr_device_info["identifiers"] == {(DOMAIN, str(mock_device_id))}
assert (
sensor._attr_device_info["configuration_url"]
== "https://www.wolf-smartset.com/"
)
assert sensor._attr_device_info["manufacturer"] == MANUFACTURER
# Test native_value property
mock_coordinator.data = {mock_parameter.parameter_id: ("value_id", "state")}
assert sensor.native_value == "state"
# Test extra_state_attributes property
assert sensor.extra_state_attributes == {
"parameter_id": mock_parameter.parameter_id,
"value_id": mock_parameter.value_id,
"parent": mock_parameter.parent,
}