From ff21c02cb6373fe662c086579ffd659dff9bc94d Mon Sep 17 00:00:00 2001 From: Tucker Kern <mill1000@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:53:52 -0700 Subject: [PATCH] Add preset modes to ESPHome fan entities (#103781) Co-authored-by: J. Nick Koston <nick@koston.org> --- homeassistant/components/esphome/fan.py | 17 +++++++++++++++++ tests/components/esphome/test_fan.py | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/homeassistant/components/esphome/fan.py b/homeassistant/components/esphome/fan.py index 9942498e12d..08135e1a702 100644 --- a/homeassistant/components/esphome/fan.py +++ b/homeassistant/components/esphome/fan.py @@ -105,6 +105,10 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity): key=self._key, direction=_FAN_DIRECTIONS.from_hass(direction) ) + async def async_set_preset_mode(self, preset_mode: str) -> None: + """Set the preset mode of the fan.""" + await self._client.fan_command(key=self._key, preset_mode=preset_mode) + @property @esphome_state_property def is_on(self) -> bool | None: @@ -144,6 +148,17 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity): """Return the current fan direction.""" return _FAN_DIRECTIONS.from_esphome(self._state.direction) + @property + @esphome_state_property + def preset_mode(self) -> str | None: + """Return the current fan preset mode.""" + return self._state.preset_mode + + @property + def preset_modes(self) -> list[str] | None: + """Return the supported fan preset modes.""" + return self._static_info.supported_preset_modes + @callback def _on_static_info_update(self, static_info: EntityInfo) -> None: """Set attrs from static info.""" @@ -156,4 +171,6 @@ class EsphomeFan(EsphomeEntity[FanInfo, FanState], FanEntity): flags |= FanEntityFeature.SET_SPEED if static_info.supports_direction: flags |= FanEntityFeature.DIRECTION + if static_info.supported_preset_modes: + flags |= FanEntityFeature.PRESET_MODE self._attr_supported_features = flags diff --git a/tests/components/esphome/test_fan.py b/tests/components/esphome/test_fan.py index 99f4bbc86a9..6f383dcb6ba 100644 --- a/tests/components/esphome/test_fan.py +++ b/tests/components/esphome/test_fan.py @@ -16,12 +16,14 @@ from homeassistant.components.fan import ( ATTR_DIRECTION, ATTR_OSCILLATING, ATTR_PERCENTAGE, + ATTR_PRESET_MODE, DOMAIN as FAN_DOMAIN, SERVICE_DECREASE_SPEED, SERVICE_INCREASE_SPEED, SERVICE_OSCILLATE, SERVICE_SET_DIRECTION, SERVICE_SET_PERCENTAGE, + SERVICE_SET_PRESET_MODE, SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_ON, @@ -145,6 +147,7 @@ async def test_fan_entity_with_all_features_new_api( supports_direction=True, supports_speed=True, supports_oscillation=True, + supported_preset_modes=["Preset1", "Preset2"], ) ] states = [ @@ -154,6 +157,7 @@ async def test_fan_entity_with_all_features_new_api( oscillating=True, speed_level=3, direction=FanDirection.REVERSE, + preset_mode=None, ) ] user_service = [] @@ -270,6 +274,15 @@ async def test_fan_entity_with_all_features_new_api( ) mock_client.fan_command.reset_mock() + await hass.services.async_call( + FAN_DOMAIN, + SERVICE_SET_PRESET_MODE, + {ATTR_ENTITY_ID: "fan.test_myfan", ATTR_PRESET_MODE: "Preset1"}, + blocking=True, + ) + mock_client.fan_command.assert_has_calls([call(key=1, preset_mode="Preset1")]) + mock_client.fan_command.reset_mock() + async def test_fan_entity_with_no_features_new_api( hass: HomeAssistant, mock_client: APIClient, mock_generic_device_entry @@ -285,6 +298,7 @@ async def test_fan_entity_with_no_features_new_api( supports_direction=False, supports_speed=False, supports_oscillation=False, + supported_preset_modes=[], ) ] states = [FanState(key=1, state=True)] -- GitLab