diff --git a/homeassistant/components/esphome/fan.py b/homeassistant/components/esphome/fan.py index 9942498e12db43a475c15c730c3c651b5d7e9d0e..08135e1a70258d2ca9e2de0f3645157aab9b5e70 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 99f4bbc86a9fe2848877c13f1d918593fade61c3..6f383dcb6ba317f9fbe81b057ee85e7c31ad0977 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)]