refactored

This commit is contained in:
EnjoyingM
2025-02-25 00:08:51 +00:00
parent ddafd17580
commit 5d840aad23
2 changed files with 132 additions and 193 deletions

View File

@@ -10,13 +10,17 @@ from wolf_comm.models import (
PercentageParameter, PercentageParameter,
PowerParameter, PowerParameter,
Pressure, Pressure,
SimpleParameter,
Temperature, Temperature,
) )
from homeassistant.components.sensor import SensorDeviceClass, SensorEntity from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
PERCENTAGE,
UnitOfEnergy, UnitOfEnergy,
UnitOfPower, UnitOfPower,
UnitOfPressure, UnitOfPressure,
@@ -37,41 +41,90 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback, async_add_entities: AddConfigEntryEntitiesCallback,
) -> None: ) -> None:
"""Set up all entries for Wolf Platform.""" """Set up all entries for Wolf Platform."""
coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR] coordinator = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]
parameters = hass.data[DOMAIN][config_entry.entry_id][PARAMETERS] parameters = hass.data[DOMAIN][config_entry.entry_id][PARAMETERS]
device_id = hass.data[DOMAIN][config_entry.entry_id][DEVICE_ID] device_id = hass.data[DOMAIN][config_entry.entry_id][DEVICE_ID]
entities: list[WolfLinkSensor] = [] entities: list[WolfLinkSensor] = [
for parameter in parameters: WolfLinkSensor(
if isinstance(parameter, Temperature): coordinator, parameter, device_id, get_entity_description(parameter)
entities.append(WolfLinkTemperature(coordinator, parameter, device_id)) )
if isinstance(parameter, Pressure): for parameter in parameters
entities.append(WolfLinkPressure(coordinator, parameter, device_id)) ]
if isinstance(parameter, EnergyParameter):
entities.append(WolfLinkEnergy(coordinator, parameter, device_id))
if isinstance(parameter, PowerParameter):
entities.append(WolfLinkPower(coordinator, parameter, device_id))
if isinstance(parameter, PercentageParameter):
entities.append(WolfLinkPercentage(coordinator, parameter, device_id))
if isinstance(parameter, ListItemParameter):
entities.append(WolfLinkState(coordinator, parameter, device_id))
if isinstance(parameter, HoursParameter):
entities.append(WolfLinkHours(coordinator, parameter, device_id))
if isinstance(parameter, SimpleParameter):
entities.append(WolfLinkSensor(coordinator, parameter, device_id))
async_add_entities(entities, True) async_add_entities(entities, True)
def get_entity_description(parameter: Parameter) -> SensorEntityDescription:
"""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(
key=parameter.parameter_id,
name=parameter.name,
)
class WolfLinkSensor(CoordinatorEntity, SensorEntity): class WolfLinkSensor(CoordinatorEntity, SensorEntity):
"""Base class for all Wolf entities.""" """Base class for all Wolf entities."""
def __init__(self, coordinator, wolf_object: Parameter, device_id) -> None: def __init__(
self,
coordinator,
wolf_object: Parameter,
device_id: str,
description: SensorEntityDescription,
) -> None:
"""Initialize.""" """Initialize."""
super().__init__(coordinator) super().__init__(coordinator)
self.entity_description = description
self.wolf_object = wolf_object self.wolf_object = wolf_object
self._attr_name = wolf_object.name self._attr_name = str(description.name)
self._attr_unique_id = f"{device_id}:{wolf_object.parameter_id}" self._attr_unique_id = f"{device_id}:{wolf_object.parameter_id}"
self._state = None self._state = None
self._attr_device_info = DeviceInfo( self._attr_device_info = DeviceInfo(
@@ -81,16 +134,28 @@ class WolfLinkSensor(CoordinatorEntity, SensorEntity):
) )
@property @property
def native_value(self): def native_value(self) -> str | None:
"""Return the state. Wolf Client is returning only changed values so we need to store old value here.""" """Return the state. Wolf Client is returning only changed values so we need to store old value here."""
if self.wolf_object.parameter_id in self.coordinator.data: if self.wolf_object.parameter_id in self.coordinator.data:
new_state = self.coordinator.data[self.wolf_object.parameter_id] new_state = self.coordinator.data[self.wolf_object.parameter_id]
self.wolf_object.value_id = new_state[0] self.wolf_object.value_id = new_state[0]
self._state = new_state[1] self._state = new_state[1]
if (
isinstance(self.wolf_object, ListItemParameter)
and self._state is not None
):
resolved_state = [
item
for item in self.wolf_object.items
if item.value == int(self._state)
]
if resolved_state:
resolved_name = resolved_state[0].name
self._state = STATES.get(resolved_name, resolved_name)
return self._state return self._state
@property @property
def extra_state_attributes(self): def extra_state_attributes(self) -> dict[str, str | None]:
"""Return the state attributes.""" """Return the state attributes."""
return { return {
"parameter_id": self.wolf_object.parameter_id, "parameter_id": self.wolf_object.parameter_id,
@@ -98,65 +163,9 @@ class WolfLinkSensor(CoordinatorEntity, SensorEntity):
"parent": self.wolf_object.parent, "parent": self.wolf_object.parent,
} }
class WolfLinkHours(WolfLinkSensor):
"""Class for hour based entities."""
_attr_icon = "mdi:clock"
_attr_native_unit_of_measurement = UnitOfTime.HOURS
class WolfLinkTemperature(WolfLinkSensor):
"""Class for temperature based entities."""
_attr_device_class = SensorDeviceClass.TEMPERATURE
_attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
class WolfLinkPressure(WolfLinkSensor):
"""Class for pressure based entities."""
_attr_device_class = SensorDeviceClass.PRESSURE
_attr_native_unit_of_measurement = UnitOfPressure.BAR
class WolfLinkPower(WolfLinkSensor):
"""Class for power based entities."""
_attr_device_class = SensorDeviceClass.POWER
_attr_native_unit_of_measurement = UnitOfPower.KILO_WATT
class WolfLinkEnergy(WolfLinkSensor):
"""Class for energy based entities."""
_attr_device_class = SensorDeviceClass.ENERGY
_attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR
class WolfLinkPercentage(WolfLinkSensor):
"""Class for percentage based entities."""
@property @property
def native_unit_of_measurement(self): def native_unit_of_measurement(self) -> str | None:
"""Return the unit the value is expressed in.""" """Return the unit the value is expressed in."""
return self.wolf_object.unit if isinstance(self.wolf_object, PercentageParameter):
return self.wolf_object.unit
return self.entity_description.native_unit_of_measurement
class WolfLinkState(WolfLinkSensor):
"""Class for entities which has defined list of state."""
_attr_translation_key = "state"
@property
def native_value(self):
"""Return the state converting with supported values."""
state = super().native_value
if state is not None:
resolved_state = [
item for item in self.wolf_object.items if item.value == int(state)
]
if resolved_state:
resolved_name = resolved_state[0].name
return STATES.get(resolved_name, resolved_name)
return state

View File

@@ -3,7 +3,16 @@
from unittest.mock import MagicMock from unittest.mock import MagicMock
import pytest import pytest
from wolf_comm import EnergyParameter, PowerParameter from wolf_comm import (
PERCENTAGE,
EnergyParameter,
HoursParameter,
Parameter,
PercentageParameter,
PowerParameter,
Pressure,
Temperature,
)
from homeassistant.components.wolflink.const import ( from homeassistant.components.wolflink.const import (
COORDINATOR, COORDINATOR,
@@ -12,18 +21,8 @@ from homeassistant.components.wolflink.const import (
MANUFACTURER, MANUFACTURER,
PARAMETERS, PARAMETERS,
) )
from homeassistant.components.wolflink.sensor import ( from homeassistant.components.wolflink.sensor import WolfLinkSensor, async_setup_entry
WolfLinkEnergy,
WolfLinkHours,
WolfLinkPercentage,
WolfLinkPower,
WolfLinkPressure,
WolfLinkSensor,
WolfLinkTemperature,
async_setup_entry,
)
from homeassistant.const import ( from homeassistant.const import (
PERCENTAGE,
UnitOfEnergy, UnitOfEnergy,
UnitOfPower, UnitOfPower,
UnitOfPressure, UnitOfPressure,
@@ -69,7 +68,7 @@ def test_wolflink_sensor_native_value(mock_coordinator: MagicMock) -> None:
"""Test WolflinkSensor native value.""" """Test WolflinkSensor native value."""
parameter = MagicMock() parameter = MagicMock()
parameter.parameter_id = "outside_temp" parameter.parameter_id = "outside_temp"
sensor = WolfLinkSensor(mock_coordinator, parameter, "mock_device_id") sensor = WolfLinkSensor(mock_coordinator, parameter, "mock_device_id", MagicMock())
mock_coordinator.data = {"outside_temp": [None, 20]} mock_coordinator.data = {"outside_temp": [None, 20]}
assert sensor.native_value == 20 assert sensor.native_value == 20
@@ -80,85 +79,41 @@ def test_wolflink_sensor_extra_state_attributes(mock_coordinator: MagicMock) ->
parameter.parameter_id = "outside_temp" parameter.parameter_id = "outside_temp"
parameter.value_id = "value_id" parameter.value_id = "value_id"
parameter.parent = "parent" parameter.parent = "parent"
sensor = WolfLinkSensor(mock_coordinator, parameter, "mock_device_id") sensor = WolfLinkSensor(mock_coordinator, parameter, "mock_device_id", MagicMock())
attributes = sensor.extra_state_attributes attributes = sensor.extra_state_attributes
assert attributes["parameter_id"] == "outside_temp" assert attributes["parameter_id"] == "outside_temp"
assert attributes["value_id"] == "value_id" assert attributes["value_id"] == "value_id"
assert attributes["parent"] == "parent" assert attributes["parent"] == "parent"
def test_wolflink_temperature_initialization(mock_coordinator: MagicMock) -> None: @pytest.mark.parametrize(
"""Test WolflinkTemperature initialization.""" ("parameter", "expected_class", "expected_unit"),
parameter = MagicMock() [
parameter.name = "Outside Temperature" (MagicMock(spec=EnergyParameter), WolfLinkSensor, UnitOfEnergy.KILO_WATT_HOUR),
parameter.parameter_id = "outside_temp" (MagicMock(spec=PowerParameter), WolfLinkSensor, UnitOfPower.KILO_WATT),
sensor = WolfLinkTemperature(mock_coordinator, parameter, "mock_device_id") (MagicMock(spec=Pressure), WolfLinkSensor, UnitOfPressure.BAR),
assert sensor._attr_device_class == "temperature" (MagicMock(spec=Temperature), WolfLinkSensor, UnitOfTemperature.CELSIUS),
assert sensor._attr_native_unit_of_measurement == UnitOfTemperature.CELSIUS (MagicMock(spec=PercentageParameter), WolfLinkSensor, PERCENTAGE),
(MagicMock(spec=HoursParameter), WolfLinkSensor, UnitOfTime.HOURS),
],
def test_wolflink_pressure_initialization(mock_coordinator: MagicMock) -> None: )
"""Test WolflinkPressure initialization.""" async def test_async_setup_entry(
parameter = MagicMock() hass: HomeAssistant,
parameter.name = "Pressure" mock_coordinator: MagicMock,
parameter.parameter_id = "pressure" parameter: Parameter,
sensor = WolfLinkPressure(mock_coordinator, parameter, "mock_device_id") expected_class: type,
assert sensor._attr_device_class == "pressure" expected_unit: str,
assert sensor._attr_native_unit_of_measurement == UnitOfPressure.BAR
def test_wolflink_power_initialization(mock_coordinator: MagicMock) -> None:
"""Test WolflinkPower initialization."""
parameter = MagicMock()
parameter.name = "Power"
parameter.parameter_id = "power"
sensor = WolfLinkPower(mock_coordinator, parameter, "mock_device_id")
assert sensor._attr_device_class == "power"
assert sensor._attr_native_unit_of_measurement == UnitOfPower.KILO_WATT
def test_wolflink_energy_initialization(mock_coordinator: MagicMock) -> None:
"""Test WolflinkEnergy initialization."""
parameter = MagicMock()
parameter.name = "Energy"
parameter.parameter_id = "energy"
sensor = WolfLinkEnergy(mock_coordinator, parameter, "mock_device_id")
assert sensor._attr_device_class == "energy"
assert sensor._attr_native_unit_of_measurement == UnitOfEnergy.KILO_WATT_HOUR
def test_wolflink_percentage_initialization(mock_coordinator: MagicMock) -> None:
"""Test WolflinkPercentage initialization."""
parameter = MagicMock()
parameter.name = "Percentage"
parameter.parameter_id = "percentage"
parameter.unit = PERCENTAGE
sensor = WolfLinkPercentage(mock_coordinator, parameter, "mock_device_id")
assert sensor.native_unit_of_measurement == PERCENTAGE
def test_wolflink_hours_initialization(mock_coordinator: MagicMock) -> None:
"""Test WolflinkHours initialization."""
parameter = MagicMock()
parameter.name = "Hours"
parameter.parameter_id = "hours"
sensor = WolfLinkHours(mock_coordinator, parameter, "mock_device_id")
assert sensor._attr_icon == "mdi:clock"
assert sensor._attr_native_unit_of_measurement == UnitOfTime.HOURS
async def test_async_setup_entry_wolflink_energy(
hass: HomeAssistant, mock_coordinator: MagicMock
) -> None: ) -> None:
"""Test async_setup_entry for WolfLinkEnergy.""" """Test async_setup_entry for various parameter types."""
config_entry = MockConfigEntry( config_entry = MockConfigEntry(
domain=DOMAIN, unique_id=str(CONFIG[DEVICE_ID]), data=CONFIG domain=DOMAIN, unique_id=str(CONFIG[DEVICE_ID]), data=CONFIG
) )
config_entry.add_to_hass(hass) config_entry.add_to_hass(hass)
parameter = MagicMock(spec=EnergyParameter) parameter.parameter_id = "param_id"
parameter.parameter_id = "energy_param" parameter.name = "Parameter"
parameter.name = "Energy" if isinstance(parameter, PercentageParameter):
parameter.unit = PERCENTAGE
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = { hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = {
PARAMETERS: [parameter], PARAMETERS: [parameter],
COORDINATOR: mock_coordinator, COORDINATOR: mock_coordinator,
@@ -171,31 +126,6 @@ async def test_async_setup_entry_wolflink_energy(
assert async_add_entities.call_count == 1 assert async_add_entities.call_count == 1
entities = async_add_entities.call_args[0][0] entities = async_add_entities.call_args[0][0]
assert len(entities) == 1 assert len(entities) == 1
assert isinstance(entities[0], WolfLinkEnergy) entity = entities[0]
assert isinstance(entity, expected_class)
assert entity.native_unit_of_measurement == expected_unit
async def test_async_setup_entry_wolflink_power(
hass: HomeAssistant, mock_coordinator: MagicMock
) -> None:
"""Test async_setup_entry for WolfLinkPower."""
config_entry = MockConfigEntry(
domain=DOMAIN, unique_id=str(CONFIG[DEVICE_ID]), data=CONFIG
)
config_entry.add_to_hass(hass)
parameter = MagicMock(spec=PowerParameter)
parameter.parameter_id = "power_param"
parameter.name = "Power"
hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = {
PARAMETERS: [parameter],
COORDINATOR: mock_coordinator,
DEVICE_ID: "mock_device_id",
}
async_add_entities = MagicMock()
await async_setup_entry(hass, config_entry, async_add_entities)
assert async_add_entities.call_count == 1
entities = async_add_entities.call_args[0][0]
assert len(entities) == 1
assert isinstance(entities[0], WolfLinkPower)