mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 06:07:17 +00:00
Improve Home Connect oven cavity temperature sensor (#139355)
* Improve oven cavity temperature translation * Fetch cavity temperature unit * Handle generic Home Connect error * Improve test clarity
This commit is contained in:
parent
2694828451
commit
5be7f49146
@ -4,6 +4,8 @@ from typing import cast
|
|||||||
|
|
||||||
from aiohomeconnect.model import EventKey, OptionKey, ProgramKey, SettingKey, StatusKey
|
from aiohomeconnect.model import EventKey, OptionKey, ProgramKey, SettingKey, StatusKey
|
||||||
|
|
||||||
|
from homeassistant.const import UnitOfTemperature, UnitOfTime, UnitOfVolume
|
||||||
|
|
||||||
from .utils import bsh_key_to_translation_key
|
from .utils import bsh_key_to_translation_key
|
||||||
|
|
||||||
DOMAIN = "home_connect"
|
DOMAIN = "home_connect"
|
||||||
@ -21,6 +23,13 @@ APPLIANCES_WITH_PROGRAMS = (
|
|||||||
"WasherDryer",
|
"WasherDryer",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
UNIT_MAP = {
|
||||||
|
"seconds": UnitOfTime.SECONDS,
|
||||||
|
"ml": UnitOfVolume.MILLILITERS,
|
||||||
|
"°C": UnitOfTemperature.CELSIUS,
|
||||||
|
"°F": UnitOfTemperature.FAHRENHEIT,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BSH_POWER_ON = "BSH.Common.EnumType.PowerState.On"
|
BSH_POWER_ON = "BSH.Common.EnumType.PowerState.On"
|
||||||
BSH_POWER_OFF = "BSH.Common.EnumType.PowerState.Off"
|
BSH_POWER_OFF = "BSH.Common.EnumType.PowerState.Off"
|
||||||
|
@ -11,7 +11,6 @@ from homeassistant.components.number import (
|
|||||||
NumberEntity,
|
NumberEntity,
|
||||||
NumberEntityDescription,
|
NumberEntityDescription,
|
||||||
)
|
)
|
||||||
from homeassistant.const import UnitOfTemperature, UnitOfTime, UnitOfVolume
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
@ -23,6 +22,7 @@ from .const import (
|
|||||||
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID,
|
SVE_TRANSLATION_PLACEHOLDER_ENTITY_ID,
|
||||||
SVE_TRANSLATION_PLACEHOLDER_KEY,
|
SVE_TRANSLATION_PLACEHOLDER_KEY,
|
||||||
SVE_TRANSLATION_PLACEHOLDER_VALUE,
|
SVE_TRANSLATION_PLACEHOLDER_VALUE,
|
||||||
|
UNIT_MAP,
|
||||||
)
|
)
|
||||||
from .coordinator import HomeConnectApplianceData, HomeConnectConfigEntry
|
from .coordinator import HomeConnectApplianceData, HomeConnectConfigEntry
|
||||||
from .entity import HomeConnectEntity, HomeConnectOptionEntity
|
from .entity import HomeConnectEntity, HomeConnectOptionEntity
|
||||||
@ -32,13 +32,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
PARALLEL_UPDATES = 1
|
PARALLEL_UPDATES = 1
|
||||||
|
|
||||||
UNIT_MAP = {
|
|
||||||
"seconds": UnitOfTime.SECONDS,
|
|
||||||
"ml": UnitOfVolume.MILLILITERS,
|
|
||||||
"°C": UnitOfTemperature.CELSIUS,
|
|
||||||
"°F": UnitOfTemperature.FAHRENHEIT,
|
|
||||||
}
|
|
||||||
|
|
||||||
NUMBERS = (
|
NUMBERS = (
|
||||||
NumberEntityDescription(
|
NumberEntityDescription(
|
||||||
key=SettingKey.REFRIGERATION_FRIDGE_FREEZER_SETPOINT_TEMPERATURE_REFRIGERATOR,
|
key=SettingKey.REFRIGERATION_FRIDGE_FREEZER_SETPOINT_TEMPERATURE_REFRIGERATOR,
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
"""Provides a sensor for Home Connect."""
|
"""Provides a sensor for Home Connect."""
|
||||||
|
|
||||||
|
import contextlib
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from aiohomeconnect.model import EventKey, StatusKey
|
from aiohomeconnect.model import EventKey, StatusKey
|
||||||
|
from aiohomeconnect.model.error import HomeConnectError
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
@ -23,6 +25,7 @@ from .const import (
|
|||||||
BSH_OPERATION_STATE_FINISHED,
|
BSH_OPERATION_STATE_FINISHED,
|
||||||
BSH_OPERATION_STATE_PAUSE,
|
BSH_OPERATION_STATE_PAUSE,
|
||||||
BSH_OPERATION_STATE_RUN,
|
BSH_OPERATION_STATE_RUN,
|
||||||
|
UNIT_MAP,
|
||||||
)
|
)
|
||||||
from .coordinator import HomeConnectApplianceData, HomeConnectConfigEntry
|
from .coordinator import HomeConnectApplianceData, HomeConnectConfigEntry
|
||||||
from .entity import HomeConnectEntity
|
from .entity import HomeConnectEntity
|
||||||
@ -40,6 +43,7 @@ class HomeConnectSensorEntityDescription(
|
|||||||
|
|
||||||
default_value: str | None = None
|
default_value: str | None = None
|
||||||
appliance_types: tuple[str, ...] | None = None
|
appliance_types: tuple[str, ...] | None = None
|
||||||
|
fetch_unit: bool = False
|
||||||
|
|
||||||
|
|
||||||
BSH_PROGRAM_SENSORS = (
|
BSH_PROGRAM_SENSORS = (
|
||||||
@ -183,7 +187,8 @@ SENSORS = (
|
|||||||
key=StatusKey.COOKING_OVEN_CURRENT_CAVITY_TEMPERATURE,
|
key=StatusKey.COOKING_OVEN_CURRENT_CAVITY_TEMPERATURE,
|
||||||
device_class=SensorDeviceClass.TEMPERATURE,
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
translation_key="current_cavity_temperature",
|
translation_key="oven_current_cavity_temperature",
|
||||||
|
fetch_unit=True,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -318,6 +323,29 @@ class HomeConnectSensor(HomeConnectEntity, SensorEntity):
|
|||||||
case _:
|
case _:
|
||||||
self._attr_native_value = status
|
self._attr_native_value = status
|
||||||
|
|
||||||
|
async def async_added_to_hass(self) -> None:
|
||||||
|
"""When entity is added to hass."""
|
||||||
|
await super().async_added_to_hass()
|
||||||
|
if self.entity_description.fetch_unit:
|
||||||
|
data = self.appliance.status[cast(StatusKey, self.bsh_key)]
|
||||||
|
if data.unit:
|
||||||
|
self._attr_native_unit_of_measurement = UNIT_MAP.get(
|
||||||
|
data.unit, data.unit
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await self.fetch_unit()
|
||||||
|
|
||||||
|
async def fetch_unit(self) -> None:
|
||||||
|
"""Fetch the unit of measurement."""
|
||||||
|
with contextlib.suppress(HomeConnectError):
|
||||||
|
data = await self.coordinator.client.get_status_value(
|
||||||
|
self.appliance.info.ha_id, status_key=cast(StatusKey, self.bsh_key)
|
||||||
|
)
|
||||||
|
if data.unit:
|
||||||
|
self._attr_native_unit_of_measurement = UNIT_MAP.get(
|
||||||
|
data.unit, data.unit
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class HomeConnectProgramSensor(HomeConnectSensor):
|
class HomeConnectProgramSensor(HomeConnectSensor):
|
||||||
"""Sensor class for Home Connect sensors that reports information related to the running program."""
|
"""Sensor class for Home Connect sensors that reports information related to the running program."""
|
||||||
|
@ -1529,8 +1529,8 @@
|
|||||||
"map3": "Map 3"
|
"map3": "Map 3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"current_cavity_temperature": {
|
"oven_current_cavity_temperature": {
|
||||||
"name": "Current cavity temperature"
|
"name": "Current oven cavity temperature"
|
||||||
},
|
},
|
||||||
"freezer_door_alarm": {
|
"freezer_door_alarm": {
|
||||||
"name": "Freezer door alarm",
|
"name": "Freezer door alarm",
|
||||||
|
@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, MagicMock
|
|||||||
|
|
||||||
from aiohomeconnect.model import (
|
from aiohomeconnect.model import (
|
||||||
ArrayOfEvents,
|
ArrayOfEvents,
|
||||||
|
ArrayOfStatus,
|
||||||
Event,
|
Event,
|
||||||
EventKey,
|
EventKey,
|
||||||
EventMessage,
|
EventMessage,
|
||||||
@ -565,3 +566,85 @@ async def test_sensors_states(
|
|||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.is_state(entity_id, expected)
|
assert hass.states.is_state(entity_id, expected)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
(
|
||||||
|
"appliance_ha_id",
|
||||||
|
"entity_id",
|
||||||
|
"status_key",
|
||||||
|
"unit_get_status",
|
||||||
|
"unit_get_status_value",
|
||||||
|
"get_status_value_call_count",
|
||||||
|
),
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"Oven",
|
||||||
|
"sensor.oven_current_oven_cavity_temperature",
|
||||||
|
StatusKey.COOKING_OVEN_CURRENT_CAVITY_TEMPERATURE,
|
||||||
|
"°C",
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Oven",
|
||||||
|
"sensor.oven_current_oven_cavity_temperature",
|
||||||
|
StatusKey.COOKING_OVEN_CURRENT_CAVITY_TEMPERATURE,
|
||||||
|
None,
|
||||||
|
"°C",
|
||||||
|
1,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
indirect=["appliance_ha_id"],
|
||||||
|
)
|
||||||
|
async def test_sensor_unit_fetching(
|
||||||
|
appliance_ha_id: str,
|
||||||
|
entity_id: str,
|
||||||
|
status_key: StatusKey,
|
||||||
|
unit_get_status: str | None,
|
||||||
|
unit_get_status_value: str | None,
|
||||||
|
get_status_value_call_count: int,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
||||||
|
setup_credentials: None,
|
||||||
|
client: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test that the sensor entities are capable of fetching units."""
|
||||||
|
|
||||||
|
async def get_status_mock(ha_id: str) -> ArrayOfStatus:
|
||||||
|
if ha_id != appliance_ha_id:
|
||||||
|
return ArrayOfStatus([])
|
||||||
|
return ArrayOfStatus(
|
||||||
|
[
|
||||||
|
Status(
|
||||||
|
key=status_key,
|
||||||
|
raw_key=status_key.value,
|
||||||
|
value=0,
|
||||||
|
unit=unit_get_status,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
client.get_status = AsyncMock(side_effect=get_status_mock)
|
||||||
|
client.get_status_value = AsyncMock(
|
||||||
|
return_value=Status(
|
||||||
|
key=status_key,
|
||||||
|
raw_key=status_key.value,
|
||||||
|
value=0,
|
||||||
|
unit=unit_get_status_value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||||
|
assert await integration_setup(client)
|
||||||
|
assert config_entry.state == ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
entity_state = hass.states.get(entity_id)
|
||||||
|
assert entity_state
|
||||||
|
assert (
|
||||||
|
entity_state.attributes["unit_of_measurement"] == unit_get_status
|
||||||
|
or unit_get_status_value
|
||||||
|
)
|
||||||
|
|
||||||
|
assert client.get_status_value.call_count == get_status_value_call_count
|
||||||
|
Loading…
x
Reference in New Issue
Block a user