1
0
mirror of https://github.com/home-assistant/core.git synced 2026-02-15 07:36:16 +00:00

Add cavity-aware oven sensors for Whirlpool (#145145)

Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
This commit is contained in:
MizterB
2025-10-23 14:03:32 -04:00
committed by GitHub
parent 439fc18860
commit e0d404456b
11 changed files with 1082 additions and 3 deletions

View File

@@ -74,6 +74,7 @@ async def authenticate(
not appliances_manager.aircons
and not appliances_manager.washers
and not appliances_manager.dryers
and not appliances_manager.ovens
):
return "no_appliances"

View File

@@ -3,6 +3,7 @@
import logging
from whirlpool.appliance import Appliance
from whirlpool.oven import Cavity as OvenCavity, Oven
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
@@ -64,3 +65,31 @@ class WhirlpoolEntity(Entity):
translation_domain=DOMAIN,
translation_key="request_failed",
)
class WhirlpoolOvenEntity(WhirlpoolEntity):
"""Base class for Whirlpool oven entities."""
_appliance: Oven
def __init__(
self,
appliance: Oven,
cavity: OvenCavity,
translation_key_base: str | None,
unique_id_suffix: str = "",
) -> None:
"""Initialize the entity."""
self.cavity = cavity
cavity_suffix = ""
if appliance.get_oven_cavity_exists(
OvenCavity.Upper
) and appliance.get_oven_cavity_exists(OvenCavity.Lower):
if cavity == OvenCavity.Upper:
cavity_suffix = "_upper"
elif cavity == OvenCavity.Lower:
cavity_suffix = "_lower"
super().__init__(
appliance, unique_id_suffix=f"{unique_id_suffix}{cavity_suffix}"
)
self._attr_translation_key = f"{translation_key_base}{cavity_suffix}"

View File

@@ -6,6 +6,15 @@
},
"dryer_state": {
"default": "mdi:tumble-dryer"
},
"oven_state": {
"default": "mdi:stove"
},
"oven_state_upper": {
"default": "mdi:stove"
},
"oven_state_lower": {
"default": "mdi:stove"
}
}
}

View File

@@ -8,6 +8,12 @@ from typing import override
from whirlpool.appliance import Appliance
from whirlpool.dryer import Dryer, MachineState as DryerMachineState
from whirlpool.oven import (
Cavity as OvenCavity,
CavityState as OvenCavityState,
CookMode,
Oven,
)
from whirlpool.washer import MachineState as WasherMachineState, Washer
from homeassistant.components.sensor import (
@@ -15,14 +21,16 @@ from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import UnitOfTemperature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.typing import StateType
from homeassistant.util.dt import utcnow
from . import WhirlpoolConfigEntry
from .entity import WhirlpoolEntity
from .entity import WhirlpoolEntity, WhirlpoolOvenEntity
PARALLEL_UPDATES = 1
SCAN_INTERVAL = timedelta(minutes=5)
@@ -88,6 +96,23 @@ STATE_CYCLE_SOAKING = "cycle_soaking"
STATE_CYCLE_SPINNING = "cycle_spinning"
STATE_CYCLE_WASHING = "cycle_washing"
OVEN_CAVITY_STATE = {
OvenCavityState.Standby: "standby",
OvenCavityState.Preheating: "preheating",
OvenCavityState.Cooking: "cooking",
}
OVEN_COOK_MODE = {
CookMode.Standby: "standby",
CookMode.Bake: "bake",
CookMode.ConvectBake: "convection_bake",
CookMode.Broil: "broil",
CookMode.ConvectBroil: "convection_broil",
CookMode.ConvectRoast: "convection_roast",
CookMode.KeepWarm: "keep_warm",
CookMode.AirFry: "air_fry",
}
def washer_state(washer: Washer) -> str | None:
"""Determine correct states for a washer."""
@@ -183,6 +208,59 @@ WASHER_DRYER_TIME_SENSORS: tuple[SensorEntityDescription] = (
)
@dataclass(frozen=True, kw_only=True)
class WhirlpoolOvenCavitySensorEntityDescription(SensorEntityDescription):
"""Describes a Whirlpool oven cavity sensor entity."""
value_fn: Callable[[Oven, OvenCavity], str | int | float | None]
OVEN_CAVITY_SENSORS: tuple[WhirlpoolOvenCavitySensorEntityDescription, ...] = (
WhirlpoolOvenCavitySensorEntityDescription(
key="oven_state",
translation_key="oven_state",
device_class=SensorDeviceClass.ENUM,
options=list(OVEN_CAVITY_STATE.values()),
value_fn=lambda oven, cavity: (
OVEN_CAVITY_STATE.get(state)
if (state := oven.get_cavity_state(cavity)) is not None
else None
),
),
WhirlpoolOvenCavitySensorEntityDescription(
key="oven_cook_mode",
translation_key="oven_cook_mode",
device_class=SensorDeviceClass.ENUM,
options=list(OVEN_COOK_MODE.values()),
value_fn=lambda oven, cavity: (
OVEN_COOK_MODE.get(cook_mode)
if (cook_mode := oven.get_cook_mode(cavity)) is not None
else None
),
),
WhirlpoolOvenCavitySensorEntityDescription(
key="oven_current_temperature",
translation_key="oven_current_temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
value_fn=lambda oven, cavity: (
temp if (temp := oven.get_temp(cavity)) != 0 else None
),
),
WhirlpoolOvenCavitySensorEntityDescription(
key="oven_target_temperature",
translation_key="oven_target_temperature",
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
value_fn=lambda oven, cavity: (
temp if (temp := oven.get_target_temp(cavity)) != 0 else None
),
),
)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: WhirlpoolConfigEntry,
@@ -215,12 +293,28 @@ async def async_setup_entry(
for description in WASHER_DRYER_TIME_SENSORS
]
oven_upper_cavity_sensors = [
WhirlpoolOvenCavitySensor(oven, OvenCavity.Upper, description)
for oven in appliances_manager.ovens
if oven.get_oven_cavity_exists(OvenCavity.Upper)
for description in OVEN_CAVITY_SENSORS
]
oven_lower_cavity_sensors = [
WhirlpoolOvenCavitySensor(oven, OvenCavity.Lower, description)
for oven in appliances_manager.ovens
if oven.get_oven_cavity_exists(OvenCavity.Lower)
for description in OVEN_CAVITY_SENSORS
]
async_add_entities(
[
*washer_sensors,
*washer_time_sensors,
*dryer_sensors,
*dryer_time_sensors,
*oven_upper_cavity_sensors,
*oven_lower_cavity_sensors,
]
)
@@ -333,3 +427,26 @@ class DryerTimeSensor(WasherDryerTimeSensorBase):
def _is_machine_state_running(self) -> bool:
"""Return true if the machine is in a running state."""
return self._appliance.get_machine_state() is DryerMachineState.RunningMainCycle
class WhirlpoolOvenCavitySensor(WhirlpoolOvenEntity, SensorEntity):
"""A class for Whirlpool oven cavity sensors."""
def __init__(
self,
oven: Oven,
cavity: OvenCavity,
description: WhirlpoolOvenCavitySensorEntityDescription,
) -> None:
"""Initialize the oven cavity sensor."""
super().__init__(
oven, cavity, description.translation_key, f"-{description.key}"
)
self.entity_description: WhirlpoolOvenCavitySensorEntityDescription = (
description
)
@property
def native_value(self) -> StateType:
"""Return native value of sensor."""
return self.entity_description.value_fn(self._appliance, self.cavity)

View File

@@ -120,6 +120,87 @@
},
"end_time": {
"name": "End time"
},
"oven_state": {
"name": "State",
"state": {
"standby": "[%key:common::state::standby%]",
"preheating": "Preheating",
"cooking": "Cooking"
}
},
"oven_state_upper": {
"name": "Upper oven state",
"state": {
"standby": "[%key:common::state::standby%]",
"preheating": "[%key:component::whirlpool::entity::sensor::oven_state::state::preheating%]",
"cooking": "[%key:component::whirlpool::entity::sensor::oven_state::state::cooking%]"
}
},
"oven_state_lower": {
"name": "Lower oven state",
"state": {
"standby": "[%key:common::state::standby%]",
"preheating": "[%key:component::whirlpool::entity::sensor::oven_state::state::preheating%]",
"cooking": "[%key:component::whirlpool::entity::sensor::oven_state::state::cooking%]"
}
},
"oven_cook_mode": {
"name": "Cook mode",
"state": {
"standby": "[%key:common::state::standby%]",
"bake": "Bake",
"convection_bake": "Convection bake",
"broil": "Broil",
"convection_broil": "Convection broil",
"convection_roast": "Convection roast",
"keep_warm": "Keep warm",
"air_fry": "Air fry"
}
},
"oven_cook_mode_upper": {
"name": "Upper oven cook mode",
"state": {
"standby": "[%key:common::state::standby%]",
"bake": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::bake%]",
"convection_bake": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::convection_bake%]",
"broil": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::broil%]",
"convection_broil": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::convection_broil%]",
"convection_roast": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::convection_roast%]",
"keep_warm": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::keep_warm%]",
"air_fry": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::air_fry%]"
}
},
"oven_cook_mode_lower": {
"name": "Lower oven cook mode",
"state": {
"standby": "[%key:common::state::standby%]",
"bake": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::bake%]",
"convection_bake": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::convection_bake%]",
"broil": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::broil%]",
"convection_broil": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::convection_broil%]",
"convection_roast": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::convection_roast%]",
"keep_warm": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::keep_warm%]",
"air_fry": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::air_fry%]"
}
},
"oven_current_temperature": {
"name": "Current temperature"
},
"oven_current_temperature_upper": {
"name": "Upper oven current temperature"
},
"oven_current_temperature_lower": {
"name": "Lower oven current temperature"
},
"oven_target_temperature": {
"name": "Target temperature"
},
"oven_target_temperature_upper": {
"name": "Upper oven target temperature"
},
"oven_target_temperature_lower": {
"name": "Lower oven target temperature"
}
}
},

View File

@@ -4,7 +4,7 @@ from unittest import mock
from unittest.mock import Mock
import pytest
from whirlpool import aircon, appliancesmanager, auth, dryer, washer
from whirlpool import aircon, appliancesmanager, auth, dryer, oven, washer
from whirlpool.backendselector import Brand, Region
from .const import MOCK_SAID1, MOCK_SAID2
@@ -49,7 +49,12 @@ def fixture_mock_auth_api():
@pytest.fixture(name="mock_appliances_manager_api", autouse=True)
def fixture_mock_appliances_manager_api(
mock_aircon1_api, mock_aircon2_api, mock_washer_api, mock_dryer_api
mock_aircon1_api,
mock_aircon2_api,
mock_washer_api,
mock_dryer_api,
mock_oven_single_cavity_api,
mock_oven_dual_cavity_api,
):
"""Set up AppliancesManager fixture."""
with (
@@ -68,6 +73,10 @@ def fixture_mock_appliances_manager_api(
]
mock_appliances_manager.return_value.washers = [mock_washer_api]
mock_appliances_manager.return_value.dryers = [mock_dryer_api]
mock_appliances_manager.return_value.ovens = [
mock_oven_single_cavity_api,
mock_oven_dual_cavity_api,
]
yield mock_appliances_manager
@@ -155,3 +164,42 @@ def mock_dryer_api():
mock_dryer.get_time_remaining.return_value = 3540
mock_dryer.get_cycle_status_sensing.return_value = False
return mock_dryer
@pytest.fixture
def mock_oven_single_cavity_api():
"""Get a mock of a single cavity oven."""
mock_oven = Mock(spec=oven.Oven, said="said_oven_single")
mock_oven.name = "Single Cavity Oven"
mock_oven.appliance_info = Mock(
data_model="oven", category="oven", model_number="12345"
)
mock_oven.get_cavity_state.return_value = oven.CavityState.Standby
mock_oven.get_cook_mode.return_value = oven.CookMode.Bake
mock_oven.get_online.return_value = True
mock_oven.get_oven_cavity_exists.side_effect = (
lambda cavity: cavity == oven.Cavity.Upper
)
mock_oven.get_temp.return_value = 180
mock_oven.get_target_temp.return_value = 200
return mock_oven
@pytest.fixture
def mock_oven_dual_cavity_api():
"""Get a mock of a dual cavity oven."""
mock_oven = Mock(spec=oven.Oven, said="said_oven_dual")
mock_oven.name = "Dual Cavity Oven"
mock_oven.appliance_info = Mock(
data_model="oven", category="oven", model_number="12345"
)
mock_oven.get_cavity_state.return_value = oven.CavityState.Standby
mock_oven.get_cook_mode.return_value = oven.CookMode.Bake
mock_oven.get_online.return_value = True
mock_oven.get_oven_cavity_exists.side_effect = lambda cavity: cavity in (
oven.Cavity.Upper,
oven.Cavity.Lower,
)
mock_oven.get_temp.return_value = 180
mock_oven.get_target_temp.return_value = 200
return mock_oven

View File

@@ -22,6 +22,16 @@
}),
}),
'ovens': dict({
'Dual Cavity Oven': dict({
'category': 'oven',
'data_model': 'oven',
'model_number': '12345',
}),
'Single Cavity Oven': dict({
'category': 'oven',
'data_model': 'oven',
'model_number': '12345',
}),
}),
'washers': dict({
'Washer': dict({

View File

@@ -145,6 +145,732 @@
'state': 'running_maincycle',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_cook_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'standby',
'bake',
'convection_bake',
'broil',
'convection_broil',
'convection_roast',
'keep_warm',
'air_fry',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_cook_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Lower oven cook mode',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_cook_mode_lower',
'unique_id': 'said_oven_dual-oven_cook_mode_lower',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_cook_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Dual cavity oven Lower oven cook mode',
'options': list([
'standby',
'bake',
'convection_bake',
'broil',
'convection_broil',
'convection_roast',
'keep_warm',
'air_fry',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_cook_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'bake',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_current_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_current_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Lower oven current temperature',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_current_temperature_lower',
'unique_id': 'said_oven_dual-oven_current_temperature_lower',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_current_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Dual cavity oven Lower oven current temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_current_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '180',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_state-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'standby',
'preheating',
'cooking',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_state',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Lower oven state',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_state_lower',
'unique_id': 'said_oven_dual-oven_state_lower',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_state-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Dual cavity oven Lower oven state',
'options': list([
'standby',
'preheating',
'cooking',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_state',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'standby',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_target_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_target_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Lower oven target temperature',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_target_temperature_lower',
'unique_id': 'said_oven_dual-oven_target_temperature_lower',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_lower_oven_target_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Dual cavity oven Lower oven target temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_lower_oven_target_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '200',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_cook_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'standby',
'bake',
'convection_bake',
'broil',
'convection_broil',
'convection_roast',
'keep_warm',
'air_fry',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_cook_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Upper oven cook mode',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_cook_mode_upper',
'unique_id': 'said_oven_dual-oven_cook_mode_upper',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_cook_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Dual cavity oven Upper oven cook mode',
'options': list([
'standby',
'bake',
'convection_bake',
'broil',
'convection_broil',
'convection_roast',
'keep_warm',
'air_fry',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_cook_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'bake',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_current_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_current_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Upper oven current temperature',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_current_temperature_upper',
'unique_id': 'said_oven_dual-oven_current_temperature_upper',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_current_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Dual cavity oven Upper oven current temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_current_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '180',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_state-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'standby',
'preheating',
'cooking',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_state',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Upper oven state',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_state_upper',
'unique_id': 'said_oven_dual-oven_state_upper',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_state-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Dual cavity oven Upper oven state',
'options': list([
'standby',
'preheating',
'cooking',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_state',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'standby',
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_target_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_target_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Upper oven target temperature',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_target_temperature_upper',
'unique_id': 'said_oven_dual-oven_target_temperature_upper',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_all_entities[sensor.dual_cavity_oven_upper_oven_target_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Dual cavity oven Upper oven target temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.dual_cavity_oven_upper_oven_target_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '200',
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_cook_mode-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'standby',
'bake',
'convection_bake',
'broil',
'convection_broil',
'convection_roast',
'keep_warm',
'air_fry',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.single_cavity_oven_cook_mode',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'Cook mode',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_cook_mode',
'unique_id': 'said_oven_single-oven_cook_mode',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_cook_mode-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Single cavity oven Cook mode',
'options': list([
'standby',
'bake',
'convection_bake',
'broil',
'convection_broil',
'convection_roast',
'keep_warm',
'air_fry',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.single_cavity_oven_cook_mode',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'bake',
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_current_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.single_cavity_oven_current_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Current temperature',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_current_temperature',
'unique_id': 'said_oven_single-oven_current_temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_current_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Single cavity oven Current temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.single_cavity_oven_current_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '180',
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_state-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'options': list([
'standby',
'preheating',
'cooking',
]),
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.single_cavity_oven_state',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENUM: 'enum'>,
'original_icon': None,
'original_name': 'State',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_state',
'unique_id': 'said_oven_single-oven_state',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_state-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'enum',
'friendly_name': 'Single cavity oven State',
'options': list([
'standby',
'preheating',
'cooking',
]),
}),
'context': <ANY>,
'entity_id': 'sensor.single_cavity_oven_state',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'standby',
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_target_temperature-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'config_subentry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.single_cavity_oven_target_temperature',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
'sensor': dict({
'suggested_display_precision': 1,
}),
}),
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
'original_icon': None,
'original_name': 'Target temperature',
'platform': 'whirlpool',
'previous_unique_id': None,
'suggested_object_id': None,
'supported_features': 0,
'translation_key': 'oven_target_temperature',
'unique_id': 'said_oven_single-oven_target_temperature',
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
})
# ---
# name: test_all_entities[sensor.single_cavity_oven_target_temperature-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'temperature',
'friendly_name': 'Single cavity oven Target temperature',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
}),
'context': <ANY>,
'entity_id': 'sensor.single_cavity_oven_target_temperature',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '200',
})
# ---
# name: test_all_entities[sensor.washer_detergent_level-entry]
EntityRegistryEntrySnapshot({
'aliases': set({

View File

@@ -210,6 +210,7 @@ async def test_no_appliances_flow(
mock_appliances_manager_api.return_value.aircons = []
mock_appliances_manager_api.return_value.washers = []
mock_appliances_manager_api.return_value.dryers = []
mock_appliances_manager_api.return_value.ovens = []
result = await hass.config_entries.flow.async_configure(
result["flow_id"], CONFIG_INPUT | {CONF_REGION: region[0], CONF_BRAND: brand[0]}
)

View File

@@ -83,6 +83,8 @@ async def test_setup_no_appliances(
mock_appliances_manager_api.return_value.aircons = []
mock_appliances_manager_api.return_value.washers = []
mock_appliances_manager_api.return_value.dryers = []
mock_appliances_manager_api.return_value.ovens = []
await init_integration(hass)
assert len(hass.states.async_all()) == 0

View File

@@ -6,6 +6,7 @@ from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion
from whirlpool.dryer import MachineState as DryerMachineState
from whirlpool.oven import CavityState as OvenCavityState, CookMode
from whirlpool.washer import MachineState as WasherMachineState
from homeassistant.components.whirlpool.sensor import SCAN_INTERVAL
@@ -312,6 +313,60 @@ async def test_washer_running_states(
(5, "active"),
],
),
(
"sensor.dual_cavity_oven_upper_oven_state",
"mock_oven_dual_cavity_api",
"get_cavity_state",
[
(OvenCavityState.Standby, "standby"),
(OvenCavityState.Preheating, "preheating"),
(OvenCavityState.Cooking, "cooking"),
(None, STATE_UNKNOWN),
],
),
(
"sensor.dual_cavity_oven_upper_oven_cook_mode",
"mock_oven_dual_cavity_api",
"get_cook_mode",
[
(CookMode.Standby, "standby"),
(CookMode.Bake, "bake"),
(CookMode.ConvectBake, "convection_bake"),
(CookMode.Broil, "broil"),
(CookMode.ConvectBroil, "convection_broil"),
(CookMode.ConvectRoast, "convection_roast"),
(CookMode.KeepWarm, "keep_warm"),
(CookMode.AirFry, "air_fry"),
(None, STATE_UNKNOWN),
],
),
(
"sensor.single_cavity_oven_state",
"mock_oven_single_cavity_api",
"get_cavity_state",
[
(OvenCavityState.Standby, "standby"),
(OvenCavityState.Preheating, "preheating"),
(OvenCavityState.Cooking, "cooking"),
(None, STATE_UNKNOWN),
],
),
(
"sensor.single_cavity_oven_cook_mode",
"mock_oven_single_cavity_api",
"get_cook_mode",
[
(CookMode.Standby, "standby"),
(CookMode.Bake, "bake"),
(CookMode.ConvectBake, "convection_bake"),
(CookMode.Broil, "broil"),
(CookMode.ConvectBroil, "convection_broil"),
(CookMode.ConvectRoast, "convection_roast"),
(CookMode.KeepWarm, "keep_warm"),
(CookMode.AirFry, "air_fry"),
(None, STATE_UNKNOWN),
],
),
],
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")