Add oven controls (number, select, button) to Whirlpool#173326
Add oven controls (number, select, button) to Whirlpool#173326bdlcalvin wants to merge 22 commits into
Conversation
There was a problem hiding this comment.
Hi @bdlcalvin
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
Hey there @abmantis, @mkmer, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds oven climate entity support to the Whirlpool integration, allowing oven cavities to be controlled via the Home Assistant climate platform with temperature control, cook mode presets, and on/off functionality.
Changes:
- Adds
OvenEntityclass toclimate.pythat represents oven cavities as climate entities with HVAC modes (OFF/HEAT), preset modes for cook modes, and temperature control. - Adds translation strings in
strings.jsonfor oven climate entity preset modes (bake, broil, air fry, etc.) for single and dual cavity ovens. - Adds comprehensive tests for the new oven climate entities covering dynamic attributes, temperature setting, preset modes, on/off, and error handling.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| homeassistant/components/whirlpool/climate.py | Adds OvenEntity class with cook mode mappings, temperature config, and HVAC/preset/temp control methods |
| homeassistant/components/whirlpool/strings.json | Adds translation keys for oven climate preset modes (single + dual cavity) |
| tests/components/whirlpool/test_climate.py | Adds parametrized tests for oven climate entity attributes, services, and error handling |
| def hvac_action(self) -> HVACAction: | ||
| """Return the current action.""" | ||
| if self._appliance.get_cavity_state(self.cavity) in OVEN_ACTIVE_STATES: | ||
| return HVACAction.HEATING | ||
| return HVACAction.OFF |
| async def test_oven_service_request_failure( | ||
| hass: HomeAssistant, | ||
| oven_climate_entity: tuple[str, str, "whirlpool.oven.Cavity"], | ||
| request: pytest.FixtureRequest, | ||
| ) -> None: | ||
| """Test a failed oven request raises HomeAssistantError.""" | ||
| entity_id, mock_fixture, _ = oven_climate_entity | ||
| mock = request.getfixturevalue(mock_fixture) | ||
| mock.set_cook.return_value = False | ||
| await init_integration(hass) | ||
|
|
||
| with pytest.raises(HomeAssistantError): | ||
| await hass.services.async_call( | ||
| CLIMATE_DOMAIN, | ||
| SERVICE_SET_TEMPERATURE, | ||
| {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 220}, | ||
| blocking=True, | ||
| ) |
| mock.get_cavity_state.return_value = whirlpool.oven.CavityState.Cooking | ||
| await trigger_attr_callback(hass, mock) | ||
| assert hass.states.get(entity_id).state == HVACMode.HEAT |
joostlek
left a comment
There was a problem hiding this comment.
So we have discussed this with other integrations before like smartthings and miele, but while these devices provide good data points for climate entities, we actually don't want them to have as climate entities. Reason for this is that climate entities are meant to control the climate of a room/area. This will lead to weird behaviors like for example asking voice to turn the temperature in the kitchen to 20 degrees, and then the oven suddenly turns to 20 degrees. Instead, having separate number and sensor entities would work better and give a more consistent experience
| 'aliases': list([ | ||
| None, | ||
| ]), |
| "climate": { | ||
| "oven": { | ||
| "state_attributes": { | ||
| "preset_mode": { | ||
| "state": { | ||
| "air_fry": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::air_fry%]", | ||
| "bake": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::bake%]", | ||
| "broil": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::broil%]", | ||
| "convection_bake": "[%key:component::whirlpool::entity::sensor::oven_cook_mode::state::convection_bake%]", | ||
| "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%]" |
|
You should break it out to one platform per PR |
joostlek
left a comment
There was a problem hiding this comment.
Please make sure we keep the PR well scoped. I think a PR per platform would fit the best
| await self._appliance.set_cook( | ||
| target_temp=value, mode=mode, cavity=self.cavity | ||
| ) |
| await hass.services.async_call( | ||
| SELECT_DOMAIN, | ||
| SERVICE_SELECT_OPTION, | ||
| {ATTR_ENTITY_ID: entity_id, ATTR_OPTION: "broil"}, | ||
| blocking=True, | ||
| ) | ||
| mock.set_cook.assert_called_once_with( | ||
| target_temp=200, mode=whirlpool.oven.CookMode.Broil, cavity=cavity | ||
| ) |
| await hass.services.async_call( | ||
| NUMBER_DOMAIN, | ||
| SERVICE_SET_VALUE, | ||
| {ATTR_ENTITY_ID: entity_id, ATTR_VALUE: 220}, | ||
| blocking=True, | ||
| ) | ||
| mock.set_cook.assert_called_once_with( | ||
| target_temp=220, mode=whirlpool.oven.CookMode.Bake, cavity=cavity | ||
| ) |
|
Splitting this into one PR per platform as requested:
Closing this combined PR in favor of those. Thanks for the reviews! |
Proposed change
Adds oven controls to the Whirlpool integration. Per review feedback (thanks @joostlek), this no longer uses a
climateentity — instead, following the SmartThings/Miele pattern, oven cavities get:numberfor the target temperature (settable),selectfor the cook mode (Bake / Convection bake / Broil / …),buttonto stop the current cook,The redundant read-only target-temperature and cook-mode sensors are removed, since the number/select now cover them. One entity set per cavity (single, or upper + lower).
The Whirlpool API couples target temp + mode into one
set_cookcall, so the number sends the temp with the current mode, the select sends the mode with the current/last temp, and the button issuesstop_cook.Type of change
Additional information