diff --git a/homeassistant/components/mqtt/fan.py b/homeassistant/components/mqtt/fan.py index 395480a041d..6009b941c5c 100644 --- a/homeassistant/components/mqtt/fan.py +++ b/homeassistant/components/mqtt/fan.py @@ -32,6 +32,7 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.reload import async_setup_reload_service from homeassistant.helpers.typing import ConfigType, HomeAssistantType from homeassistant.util.percentage import ( + int_states_in_range, ordered_list_item_to_percentage, percentage_to_ordered_list_item, percentage_to_ranged_value, @@ -224,6 +225,9 @@ class MqttFan(MqttEntity, FanEntity): self._optimistic_preset_mode = None self._optimistic_speed = None + self._legacy_speeds_list = [] + self._legacy_speeds_list_no_off = [] + MqttEntity.__init__(self, hass, config, config_entry, discovery_data) @staticmethod @@ -284,28 +288,18 @@ class MqttFan(MqttEntity, FanEntity): self._legacy_speeds_list_no_off = speed_list_without_preset_modes( self._legacy_speeds_list ) - else: - self._legacy_speeds_list = [] self._feature_percentage = CONF_PERCENTAGE_COMMAND_TOPIC in config self._feature_preset_mode = CONF_PRESET_MODE_COMMAND_TOPIC in config if self._feature_preset_mode: - self._speeds_list = speed_list_without_preset_modes( - self._legacy_speeds_list + config[CONF_PRESET_MODES_LIST] - ) - self._preset_modes = ( - self._legacy_speeds_list + config[CONF_PRESET_MODES_LIST] - ) + self._preset_modes = config[CONF_PRESET_MODES_LIST] else: - self._speeds_list = speed_list_without_preset_modes( - self._legacy_speeds_list - ) self._preset_modes = [] - if not self._speeds_list or self._feature_percentage: - self._speed_count = 100 + if self._feature_percentage: + self._speed_count = min(int_states_in_range(self._speed_range), 100) else: - self._speed_count = len(self._speeds_list) + self._speed_count = len(self._legacy_speeds_list_no_off) or 100 optimistic = config[CONF_OPTIMISTIC] self._optimistic = optimistic or self._topic[CONF_STATE_TOPIC] is None @@ -327,11 +321,7 @@ class MqttFan(MqttEntity, FanEntity): self._topic[CONF_OSCILLATION_COMMAND_TOPIC] is not None and SUPPORT_OSCILLATE ) - if self._feature_preset_mode and self._speeds_list: - self._supported_features |= SUPPORT_SET_SPEED - if self._feature_percentage: - self._supported_features |= SUPPORT_SET_SPEED - if self._feature_legacy_speeds: + if self._feature_percentage or self._feature_legacy_speeds: self._supported_features |= SUPPORT_SET_SPEED if self._feature_preset_mode: self._supported_features |= SUPPORT_PRESET_MODE @@ -414,10 +404,6 @@ class MqttFan(MqttEntity, FanEntity): return self._preset_mode = preset_mode - if not self._implemented_percentage and (preset_mode in self.speed_list): - self._percentage = ordered_list_item_to_percentage( - self.speed_list, preset_mode - ) self.async_write_ha_state() if self._topic[CONF_PRESET_MODE_STATE_TOPIC] is not None: @@ -455,10 +441,10 @@ class MqttFan(MqttEntity, FanEntity): ) return - if not self._implemented_percentage: - if speed in self._speeds_list: + if not self._feature_percentage: + if speed in self._legacy_speeds_list_no_off: self._percentage = ordered_list_item_to_percentage( - self._speeds_list, speed + self._legacy_speeds_list_no_off, speed ) elif speed == SPEED_OFF: self._percentage = 0 @@ -506,19 +492,9 @@ class MqttFan(MqttEntity, FanEntity): """Return true if device is on.""" return self._state - @property - def _implemented_percentage(self): - """Return true if percentage has been implemented.""" - return self._feature_percentage - - @property - def _implemented_preset_mode(self): - """Return true if preset_mode has been implemented.""" - return self._feature_preset_mode - # The use of legacy speeds is deprecated in the schema, support will be removed after a quarter (2021.7) @property - def _implemented_speed(self): + def _implemented_speed(self) -> bool: """Return true if speed has been implemented.""" return self._feature_legacy_speeds @@ -541,7 +517,7 @@ class MqttFan(MqttEntity, FanEntity): @property def speed_list(self) -> list: """Get the list of available speeds.""" - return self._speeds_list + return self._legacy_speeds_list_no_off @property def supported_features(self) -> int: @@ -555,7 +531,7 @@ class MqttFan(MqttEntity, FanEntity): @property def speed_count(self) -> int: - """Return the number of speeds the fan supports or 100 if percentage is supported.""" + """Return the number of speeds the fan supports.""" return self._speed_count @property @@ -620,20 +596,8 @@ class MqttFan(MqttEntity, FanEntity): percentage_to_ranged_value(self._speed_range, percentage) ) mqtt_payload = self._command_templates[ATTR_PERCENTAGE](percentage_payload) - if self._implemented_preset_mode: - if percentage: - await self.async_set_preset_mode( - preset_mode=percentage_to_ordered_list_item( - self.speed_list, percentage - ) - ) - # Legacy are deprecated in the schema, support will be removed after a quarter (2021.7) - elif self._feature_legacy_speeds and ( - SPEED_OFF in self._legacy_speeds_list - ): - await self.async_set_preset_mode(SPEED_OFF) # Legacy are deprecated in the schema, support will be removed after a quarter (2021.7) - elif self._feature_legacy_speeds: + if self._feature_legacy_speeds: if percentage: await self.async_set_speed( percentage_to_ordered_list_item( @@ -644,7 +608,7 @@ class MqttFan(MqttEntity, FanEntity): elif SPEED_OFF in self._legacy_speeds_list: await self.async_set_speed(SPEED_OFF) - if self._implemented_percentage: + if self._feature_percentage: mqtt.async_publish( self.hass, self._topic[CONF_PERCENTAGE_COMMAND_TOPIC], @@ -665,13 +629,7 @@ class MqttFan(MqttEntity, FanEntity): if preset_mode not in self.preset_modes: _LOGGER.warning("'%s'is not a valid preset mode", preset_mode) return - # Legacy are deprecated in the schema, support will be removed after a quarter (2021.7) - if preset_mode in self._legacy_speeds_list: - await self.async_set_speed(speed=preset_mode) - if not self._implemented_percentage and preset_mode in self.speed_list: - self._percentage = ordered_list_item_to_percentage( - self.speed_list, preset_mode - ) + mqtt_payload = self._command_templates[ATTR_PRESET_MODE](preset_mode) mqtt.async_publish( @@ -693,18 +651,18 @@ class MqttFan(MqttEntity, FanEntity): This method is a coroutine. """ speed_payload = None - if self._feature_legacy_speeds: + if speed in self._legacy_speeds_list: if speed == SPEED_LOW: speed_payload = self._payload["SPEED_LOW"] elif speed == SPEED_MEDIUM: speed_payload = self._payload["SPEED_MEDIUM"] elif speed == SPEED_HIGH: speed_payload = self._payload["SPEED_HIGH"] - elif speed == SPEED_OFF: - speed_payload = self._payload["SPEED_OFF"] else: - _LOGGER.warning("'%s'is not a valid speed", speed) - return + speed_payload = self._payload["SPEED_OFF"] + else: + _LOGGER.warning("'%s' is not a valid speed", speed) + return if speed_payload: mqtt.async_publish( diff --git a/tests/components/mqtt/test_fan.py b/tests/components/mqtt/test_fan.py index be32540b04d..5caec9b7473 100644 --- a/tests/components/mqtt/test_fan.py +++ b/tests/components/mqtt/test_fan.py @@ -85,11 +85,11 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog): "preset_mode_state_topic": "preset-mode-state-topic", "preset_mode_command_topic": "preset-mode-command-topic", "preset_modes": [ - "medium", - "medium-high", - "high", - "very-high", - "freaking-high", + "auto", + "smart", + "whoosh", + "eco", + "breeze", "silent", ], "speed_range_min": 1, @@ -126,6 +126,8 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog): state = hass.states.get("fan.test") assert state.attributes.get("oscillating") is False + assert state.attributes.get("percentage_step") == 1.0 + async_fire_mqtt_message(hass, "percentage-state-topic", "0") state = hass.states.get("fan.test") assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0 @@ -151,16 +153,16 @@ async def test_controlling_state_via_topic(hass, mqtt_mock, caplog): caplog.clear() async_fire_mqtt_message(hass, "preset-mode-state-topic", "low") - state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "low" + assert "not a valid preset mode" in caplog.text + caplog.clear() - async_fire_mqtt_message(hass, "preset-mode-state-topic", "medium") + async_fire_mqtt_message(hass, "preset-mode-state-topic", "auto") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "medium" + assert state.attributes.get("preset_mode") == "auto" - async_fire_mqtt_message(hass, "preset-mode-state-topic", "very-high") + async_fire_mqtt_message(hass, "preset-mode-state-topic", "eco") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "very-high" + assert state.attributes.get("preset_mode") == "eco" async_fire_mqtt_message(hass, "preset-mode-state-topic", "silent") state = hass.states.get("fan.test") @@ -256,7 +258,9 @@ async def test_controlling_state_via_topic_with_different_speed_range( caplog.clear() -async def test_controlling_state_via_topic_no_percentage_topics(hass, mqtt_mock): +async def test_controlling_state_via_topic_no_percentage_topics( + hass, mqtt_mock, caplog +): """Test the controlling state via topic without percentage topics.""" assert await async_setup_component( hass, @@ -273,9 +277,11 @@ async def test_controlling_state_via_topic_no_percentage_topics(hass, mqtt_mock) "preset_mode_state_topic": "preset-mode-state-topic", "preset_mode_command_topic": "preset-mode-command-topic", "preset_modes": [ - "high", - "freaking-high", - "silent", + "auto", + "smart", + "whoosh", + "eco", + "breeze", ], # use of speeds is deprecated, support will be removed after a quarter (2021.7) "speeds": ["off", "low", "medium"], @@ -288,57 +294,51 @@ async def test_controlling_state_via_topic_no_percentage_topics(hass, mqtt_mock) assert state.state == STATE_OFF assert not state.attributes.get(ATTR_ASSUMED_STATE) - async_fire_mqtt_message(hass, "preset-mode-state-topic", "freaking-high") + async_fire_mqtt_message(hass, "preset-mode-state-topic", "smart") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "freaking-high" - assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100 + assert state.attributes.get("preset_mode") == "smart" + assert state.attributes.get(fan.ATTR_PERCENTAGE) is None # use of speeds is deprecated, support will be removed after a quarter (2021.7) assert state.attributes.get("speed") == fan.SPEED_OFF - async_fire_mqtt_message(hass, "preset-mode-state-topic", "high") + async_fire_mqtt_message(hass, "preset-mode-state-topic", "auto") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "high" - assert state.attributes.get(fan.ATTR_PERCENTAGE) == 75 + assert state.attributes.get("preset_mode") == "auto" + assert state.attributes.get(fan.ATTR_PERCENTAGE) is None # use of speeds is deprecated, support will be removed after a quarter (2021.7) assert state.attributes.get("speed") == fan.SPEED_OFF - async_fire_mqtt_message(hass, "preset-mode-state-topic", "silent") + async_fire_mqtt_message(hass, "preset-mode-state-topic", "whoosh") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "silent" - assert state.attributes.get(fan.ATTR_PERCENTAGE) == 75 + assert state.attributes.get("preset_mode") == "whoosh" + assert state.attributes.get(fan.ATTR_PERCENTAGE) is None # use of speeds is deprecated, support will be removed after a quarter (2021.7) assert state.attributes.get("speed") == fan.SPEED_OFF async_fire_mqtt_message(hass, "preset-mode-state-topic", "medium") - state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "medium" - assert state.attributes.get(fan.ATTR_PERCENTAGE) == 50 - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - assert state.attributes.get("speed") == fan.SPEED_OFF + assert "not a valid preset mode" in caplog.text + caplog.clear() async_fire_mqtt_message(hass, "preset-mode-state-topic", "low") - state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "low" - assert state.attributes.get(fan.ATTR_PERCENTAGE) == 25 - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - assert state.attributes.get("speed") == fan.SPEED_OFF + assert "not a valid preset mode" in caplog.text + caplog.clear() # use of speeds is deprecated, support will be removed after a quarter (2021.7) async_fire_mqtt_message(hass, "speed-state-topic", "medium") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "low" - assert state.attributes.get(fan.ATTR_PERCENTAGE) == 50 + assert state.attributes.get("preset_mode") == "whoosh" + assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100 assert state.attributes.get("speed") == fan.SPEED_MEDIUM async_fire_mqtt_message(hass, "speed-state-topic", "low") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "low" - assert state.attributes.get(fan.ATTR_PERCENTAGE) == 25 + assert state.attributes.get("preset_mode") == "whoosh" + assert state.attributes.get(fan.ATTR_PERCENTAGE) == 50 assert state.attributes.get("speed") == fan.SPEED_LOW async_fire_mqtt_message(hass, "speed-state-topic", "off") state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "low" + assert state.attributes.get("preset_mode") == "whoosh" assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0 assert state.attributes.get("speed") == fan.SPEED_OFF @@ -361,11 +361,11 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap "preset_mode_state_topic": "preset-mode-state-topic", "preset_mode_command_topic": "preset-mode-command-topic", "preset_modes": [ - "medium", - "medium-high", - "high", - "very-high", - "freaking-high", + "auto", + "smart", + "whoosh", + "eco", + "breeze", "silent", ], "state_value_template": "{{ value_json.val }}", @@ -412,20 +412,20 @@ async def test_controlling_state_via_topic_and_json_message(hass, mqtt_mock, cap assert "not a valid preset mode" in caplog.text caplog.clear() - async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "medium"}') + async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "auto"}') state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "medium" + assert state.attributes.get("preset_mode") == "auto" - async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "freaking-high"}') + async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "breeze"}') state = hass.states.get("fan.test") - assert state.attributes.get("preset_mode") == "freaking-high" + assert state.attributes.get("preset_mode") == "breeze" async_fire_mqtt_message(hass, "preset-mode-state-topic", '{"val": "silent"}') state = hass.states.get("fan.test") assert state.attributes.get("preset_mode") == "silent" -async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): +async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock, caplog): """Test optimistic mode without state topic.""" assert await async_setup_component( hass, @@ -447,8 +447,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): # use of speeds is deprecated, support will be removed after a quarter (2021.7) "speeds": ["off", "low", "medium"], "preset_modes": [ - "high", - "freaking-high", + "whoosh", + "breeze", "silent", ], # use of speeds is deprecated, support will be removed after a quarter (2021.7) @@ -510,7 +510,7 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False) mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "freaking-high", 0, False + "speed-command-topic", "speed_mEdium", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") @@ -518,11 +518,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_percentage(hass, "fan.test", 0) - assert mqtt_mock.async_publish.call_count == 3 + assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "0", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "off", 0, False - ) # use of speeds is deprecated, support will be removed after a quarter (2021.7) mqtt_mock.async_publish.assert_any_call( "speed-command-topic", "speed_OfF", 0, False @@ -534,54 +531,32 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): assert state.attributes.get(fan.ATTR_SPEED) == fan.SPEED_OFF assert state.attributes.get(ATTR_ASSUMED_STATE) + # use of speeds is deprecated, support will be removed after a quarter (2021.7) await common.async_set_preset_mode(hass, "fan.test", "low") - assert mqtt_mock.async_publish.call_count == 2 - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call( - "speed-command-topic", "speed_lOw", 0, False - ) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "low", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "low" - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - assert state.attributes.get(fan.ATTR_SPEED) == fan.SPEED_LOW - assert state.attributes.get(ATTR_ASSUMED_STATE) + assert "not a valid preset mode" in caplog.text + caplog.clear() + # use of speeds is deprecated, support will be removed after a quarter (2021.7) await common.async_set_preset_mode(hass, "fan.test", "medium") - assert mqtt_mock.async_publish.call_count == 2 - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call( - "speed-command-topic", "speed_mEdium", 0, False - ) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False + assert "not a valid preset mode" in caplog.text + caplog.clear() + + await common.async_set_preset_mode(hass, "fan.test", "whoosh") + mqtt_mock.async_publish.assert_called_once_with( + "preset-mode-command-topic", "whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "medium" - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - assert state.attributes.get(fan.ATTR_SPEED) == fan.SPEED_MEDIUM + assert state.attributes.get(fan.ATTR_PRESET_MODE) == "whoosh" assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_set_preset_mode(hass, "fan.test", "high") + await common.async_set_preset_mode(hass, "fan.test", "breeze") mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "high", 0, False + "preset-mode-command-topic", "breeze", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "high" - assert state.attributes.get(ATTR_ASSUMED_STATE) - - await common.async_set_preset_mode(hass, "fan.test", "freaking-high") - mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "freaking-high", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high" + assert state.attributes.get(fan.ATTR_PRESET_MODE) == "breeze" assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_preset_mode(hass, "fan.test", "silent") @@ -615,13 +590,8 @@ async def test_sending_mqtt_commands_and_optimistic(hass, mqtt_mock): # use of speeds is deprecated, support will be removed after a quarter (2021.7) await common.async_set_speed(hass, "fan.test", fan.SPEED_HIGH) - mqtt_mock.async_publish.assert_called_once_with( - "speed-command-topic", "speed_High", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.state == STATE_OFF - assert state.attributes.get(ATTR_ASSUMED_STATE) + assert "not a valid speed" in caplog.text + caplog.clear() # use of speeds is deprecated, support will be removed after a quarter (2021.7) await common.async_set_speed(hass, "fan.test", fan.SPEED_OFF) @@ -735,8 +705,8 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c "percentage_command_topic": "percentage-command-topic", "preset_mode_command_topic": "preset-mode-command-topic", "preset_modes": [ - "high", - "freaking-high", + "whoosh", + "breeze", "silent", ], } @@ -769,14 +739,12 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c await common.async_set_percentage(hass, "fan.test", 101) await common.async_set_percentage(hass, "fan.test", 100) - mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "freaking-high", 0, False + mqtt_mock.async_publish.assert_called_once_with( + "percentage-command-topic", "100", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100 - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high" assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_percentage(hass, "fan.test", 0) @@ -793,26 +761,26 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c assert "not a valid preset mode" in caplog.text caplog.clear() - await common.async_set_preset_mode(hass, "fan.test", "medium") + await common.async_set_preset_mode(hass, "fan.test", "auto") assert "not a valid preset mode" in caplog.text caplog.clear() - await common.async_set_preset_mode(hass, "fan.test", "high") + await common.async_set_preset_mode(hass, "fan.test", "whoosh") mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "high", 0, False + "preset-mode-command-topic", "whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "high" + assert state.attributes.get(fan.ATTR_PRESET_MODE) == "whoosh" assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_set_preset_mode(hass, "fan.test", "freaking-high") + await common.async_set_preset_mode(hass, "fan.test", "breeze") mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "freaking-high", 0, False + "preset-mode-command-topic", "breeze", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high" + assert state.attributes.get(fan.ATTR_PRESET_MODE) == "breeze" assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_preset_mode(hass, "fan.test", "silent") @@ -825,12 +793,9 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_turn_on(hass, "fan.test", percentage=25) - assert mqtt_mock.async_publish.call_count == 3 + assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "25", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "high", 0, False - ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_ON @@ -843,11 +808,11 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c assert state.state == STATE_OFF assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_turn_on(hass, "fan.test", preset_mode="high") + await common.async_turn_on(hass, "fan.test", preset_mode="whoosh") assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "high", 0, False + "preset-mode-command-topic", "whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") @@ -855,7 +820,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_legacy(hass, mqtt_mock, c assert state.attributes.get(ATTR_ASSUMED_STATE) with pytest.raises(NotValidPresetModeError): - await common.async_turn_on(hass, "fan.test", preset_mode="low") + await common.async_turn_on(hass, "fan.test", preset_mode="freaking-high") async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): @@ -876,8 +841,8 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): "preset_mode_command_topic": "preset-mode-command-topic", "preset_mode_command_template": "preset_mode: {{ value }}", "preset_modes": [ - "high", - "freaking-high", + "whoosh", + "breeze", "silent", ], } @@ -914,16 +879,12 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): await common.async_set_percentage(hass, "fan.test", 101) await common.async_set_percentage(hass, "fan.test", 100) - mqtt_mock.async_publish.assert_any_call( + mqtt_mock.async_publish.assert_called_once_with( "percentage-command-topic", "percentage: 100", 0, False ) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "preset_mode: freaking-high", 0, False - ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100 - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high" assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_percentage(hass, "fan.test", 0) @@ -944,22 +905,22 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): assert "not a valid preset mode" in caplog.text caplog.clear() - await common.async_set_preset_mode(hass, "fan.test", "high") + await common.async_set_preset_mode(hass, "fan.test", "whoosh") mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "preset_mode: high", 0, False + "preset-mode-command-topic", "preset_mode: whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "high" + assert state.attributes.get(fan.ATTR_PRESET_MODE) == "whoosh" assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_set_preset_mode(hass, "fan.test", "freaking-high") + await common.async_set_preset_mode(hass, "fan.test", "breeze") mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "preset_mode: freaking-high", 0, False + "preset-mode-command-topic", "preset_mode: breeze", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) == "freaking-high" + assert state.attributes.get(fan.ATTR_PRESET_MODE) == "breeze" assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_preset_mode(hass, "fan.test", "silent") @@ -972,14 +933,11 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_turn_on(hass, "fan.test", percentage=25) - assert mqtt_mock.async_publish.call_count == 3 + assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("command-topic", "state: ON", 0, False) mqtt_mock.async_publish.assert_any_call( "percentage-command-topic", "percentage: 25", 0, False ) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "preset_mode: high", 0, False - ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_ON @@ -992,11 +950,11 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): assert state.state == STATE_OFF assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_turn_on(hass, "fan.test", preset_mode="high") + await common.async_turn_on(hass, "fan.test", preset_mode="whoosh") assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("command-topic", "state: ON", 0, False) mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "preset_mode: high", 0, False + "preset-mode-command-topic", "preset_mode: whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") @@ -1008,7 +966,7 @@ async def test_sending_mqtt_command_templates_(hass, mqtt_mock, caplog): async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic( - hass, mqtt_mock + hass, mqtt_mock, caplog ): """Test optimistic mode without state topic without percentage command topic.""" assert await async_setup_component( @@ -1027,9 +985,10 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic( # use of speeds is deprecated, support will be removed after a quarter (2021.7) "speeds": ["off", "low", "medium"], "preset_modes": [ - "high", - "freaking-high", + "whoosh", + "breeze", "silent", + "high", ], } }, @@ -1047,9 +1006,7 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic( await common.async_set_percentage(hass, "fan.test", 101) await common.async_set_percentage(hass, "fan.test", 100) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "freaking-high", 0, False - ) + mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.attributes.get(fan.ATTR_PERCENTAGE) == 100 @@ -1063,41 +1020,27 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic( assert state.attributes.get(fan.ATTR_PERCENTAGE) == 0 assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_set_preset_mode(hass, "fan.test", "low") - assert mqtt_mock.async_publish.call_count == 2 # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "low", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) is None - assert state.attributes.get(ATTR_ASSUMED_STATE) + await common.async_set_preset_mode(hass, "fan.test", "low") + assert "not a valid preset mode" in caplog.text + caplog.clear() await common.async_set_preset_mode(hass, "fan.test", "medium") - assert mqtt_mock.async_publish.call_count == 2 - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False + assert "not a valid preset mode" in caplog.text + caplog.clear() + + await common.async_set_preset_mode(hass, "fan.test", "whoosh") + mqtt_mock.async_publish.assert_called_once_with( + "preset-mode-command-topic", "whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.attributes.get(fan.ATTR_PRESET_MODE) is None assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_set_preset_mode(hass, "fan.test", "high") + await common.async_set_preset_mode(hass, "fan.test", "breeze") mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "high", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.attributes.get(fan.ATTR_PRESET_MODE) is None - assert state.attributes.get(ATTR_ASSUMED_STATE) - - await common.async_set_preset_mode(hass, "fan.test", "freaking-high") - mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "freaking-high", 0, False + "preset-mode-command-topic", "breeze", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") @@ -1133,14 +1076,8 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic( assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_speed(hass, "fan.test", fan.SPEED_HIGH) - mqtt_mock.async_publish.assert_called_once_with( - "speed-command-topic", "high", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.state == STATE_OFF - assert state.attributes.get(ATTR_ASSUMED_STATE) - + assert "not a valid speed" in caplog.text + caplog.clear() await common.async_set_speed(hass, "fan.test", fan.SPEED_OFF) mqtt_mock.async_publish.assert_any_call("speed-command-topic", "off", 0, False) @@ -1150,13 +1087,10 @@ async def test_sending_mqtt_commands_and_optimistic_no_percentage_topic( assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_turn_on(hass, "fan.test", speed="medium") - assert mqtt_mock.async_publish.call_count == 3 + assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) # use of speeds is deprecated, support will be removed after a quarter (2021.7) mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False - ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_ON @@ -1325,8 +1259,8 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca # use of speeds is deprecated, support will be removed after a quarter (2021.7) "speeds": ["off", "low", "medium"], "preset_modes": [ - "high", - "freaking-high", + "whoosh", + "breeze", "silent", ], "optimistic": True, @@ -1358,9 +1292,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) # use of speeds is deprecated, support will be removed after a quarter (2021.7) mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False - ) + mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_ON @@ -1374,11 +1306,8 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_turn_on(hass, "fan.test", percentage=25) - assert mqtt_mock.async_publish.call_count == 4 + assert mqtt_mock.async_publish.call_count == 3 mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "low", 0, False - ) mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "25", 0, False) # use of speeds is deprecated, support will be removed after a quarter (2021.7) mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False) @@ -1394,24 +1323,15 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca assert state.state == STATE_OFF assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_turn_on(hass, "fan.test", preset_mode="medium") - assert mqtt_mock.async_publish.call_count == 3 - mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False - ) # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.state == STATE_ON - assert state.attributes.get(ATTR_ASSUMED_STATE) + with pytest.raises(NotValidPresetModeError): + await common.async_turn_on(hass, "fan.test", preset_mode="auto") - await common.async_turn_on(hass, "fan.test", preset_mode="high") + await common.async_turn_on(hass, "fan.test", preset_mode="whoosh") assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "high", 0, False + "preset-mode-command-topic", "whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") @@ -1471,14 +1391,11 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_turn_on(hass, "fan.test", percentage=50) - assert mqtt_mock.async_publish.call_count == 4 + assert mqtt_mock.async_publish.call_count == 3 mqtt_mock.async_publish.assert_any_call("command-topic", "ON", 0, False) mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "50", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False - ) # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) + mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_ON @@ -1501,26 +1418,20 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_percentage(hass, "fan.test", 33) - assert mqtt_mock.async_publish.call_count == 3 + assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "33", 0, False) # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False - ) + mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_OFF assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_percentage(hass, "fan.test", 50) - assert mqtt_mock.async_publish.call_count == 3 + assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "50", 0, False) # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False - ) + mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_OFF @@ -1529,22 +1440,18 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca await common.async_set_percentage(hass, "fan.test", 100) assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "100", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "freaking-high", 0, False - ) + # use of speeds is deprecated, support will be removed after a quarter (2021.7) + mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_OFF assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_percentage(hass, "fan.test", 0) - assert mqtt_mock.async_publish.call_count == 3 + assert mqtt_mock.async_publish.call_count == 2 mqtt_mock.async_publish.assert_any_call("percentage-command-topic", "0", 0, False) # use of speeds is deprecated, support will be removed after a quarter (2021.7) mqtt_mock.async_publish.assert_any_call("speed-command-topic", "off", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "off", 0, False - ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") assert state.state == STATE_OFF @@ -1554,32 +1461,16 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca await common.async_set_percentage(hass, "fan.test", 101) await common.async_set_preset_mode(hass, "fan.test", "low") - assert mqtt_mock.async_publish.call_count == 2 - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "low", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "low", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.state == STATE_OFF - assert state.attributes.get(ATTR_ASSUMED_STATE) + assert "not a valid preset mode" in caplog.text + caplog.clear() await common.async_set_preset_mode(hass, "fan.test", "medium") - assert mqtt_mock.async_publish.call_count == 2 - # use of speeds is deprecated, support will be removed after a quarter (2021.7) - mqtt_mock.async_publish.assert_any_call("speed-command-topic", "medium", 0, False) - mqtt_mock.async_publish.assert_any_call( - "preset-mode-command-topic", "medium", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.state == STATE_OFF - assert state.attributes.get(ATTR_ASSUMED_STATE) + assert "not a valid preset mode" in caplog.text + caplog.clear() - await common.async_set_preset_mode(hass, "fan.test", "high") + await common.async_set_preset_mode(hass, "fan.test", "whoosh") mqtt_mock.async_publish.assert_called_once_with( - "preset-mode-command-topic", "high", 0, False + "preset-mode-command-topic", "whoosh", 0, False ) mqtt_mock.async_publish.reset_mock() state = hass.states.get("fan.test") @@ -1595,7 +1486,7 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca assert state.state == STATE_OFF assert state.attributes.get(ATTR_ASSUMED_STATE) - await common.async_set_preset_mode(hass, "fan.test", "ModeX") + await common.async_set_preset_mode(hass, "fan.test", "freaking-high") assert "not a valid preset mode" in caplog.text caplog.clear() @@ -1615,13 +1506,8 @@ async def test_sending_mqtt_commands_and_explicit_optimistic(hass, mqtt_mock, ca assert state.attributes.get(ATTR_ASSUMED_STATE) await common.async_set_speed(hass, "fan.test", fan.SPEED_HIGH) - mqtt_mock.async_publish.assert_called_once_with( - "speed-command-topic", "high", 0, False - ) - mqtt_mock.async_publish.reset_mock() - state = hass.states.get("fan.test") - assert state.state == STATE_OFF - assert state.attributes.get(ATTR_ASSUMED_STATE) + assert "not a valid speed" in caplog.text + caplog.clear() await common.async_set_speed(hass, "fan.test", fan.SPEED_OFF) mqtt_mock.async_publish.assert_called_once_with( @@ -1653,7 +1539,7 @@ async def test_attributes(hass, mqtt_mock, caplog): "preset_mode_command_topic": "preset-mode-command-topic", "percentage_command_topic": "percentage-command-topic", "preset_modes": [ - "freaking-high", + "breeze", "silent", ], } @@ -1667,7 +1553,6 @@ async def test_attributes(hass, mqtt_mock, caplog): "low", "medium", "high", - "freaking-high", ] await common.async_turn_on(hass, "fan.test") @@ -1821,14 +1706,14 @@ async def test_supported_features(hass, mqtt_mock): "name": "test3c2", "command_topic": "command-topic", "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["very-fast", "auto"], + "preset_modes": ["eco", "auto"], }, { "platform": "mqtt", "name": "test3c3", "command_topic": "command-topic", "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["off", "on", "auto"], + "preset_modes": ["eco", "smart", "auto"], }, { "platform": "mqtt", @@ -1863,7 +1748,7 @@ async def test_supported_features(hass, mqtt_mock): "name": "test5pr_mb", "command_topic": "command-topic", "preset_mode_command_topic": "preset-mode-command-topic", - "preset_modes": ["off", "on", "auto"], + "preset_modes": ["whoosh", "silent", "auto"], }, { "platform": "mqtt", @@ -1927,10 +1812,7 @@ async def test_supported_features(hass, mqtt_mock): assert state is None state = hass.states.get("fan.test3c2") - assert ( - state.attributes.get(ATTR_SUPPORTED_FEATURES) - == fan.SUPPORT_PRESET_MODE | fan.SUPPORT_SET_SPEED - ) + assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE state = hass.states.get("fan.test3c3") assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE @@ -1949,21 +1831,19 @@ async def test_supported_features(hass, mqtt_mock): ) state = hass.states.get("fan.test5pr_ma") - assert ( - state.attributes.get(ATTR_SUPPORTED_FEATURES) - == fan.SUPPORT_SET_SPEED | fan.SUPPORT_PRESET_MODE - ) + assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE state = hass.states.get("fan.test5pr_mb") assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_PRESET_MODE state = hass.states.get("fan.test5pr_mc") assert ( state.attributes.get(ATTR_SUPPORTED_FEATURES) - == fan.SUPPORT_OSCILLATE | fan.SUPPORT_SET_SPEED | fan.SUPPORT_PRESET_MODE + == fan.SUPPORT_OSCILLATE | fan.SUPPORT_PRESET_MODE ) state = hass.states.get("fan.test6spd_range_a") assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == fan.SUPPORT_SET_SPEED + assert state.attributes.get("percentage_step") == 2.5 state = hass.states.get("fan.test6spd_range_b") assert state is None state = hass.states.get("fan.test6spd_range_c")